I try to grant specific privileges to my table "MEMBERS" in postgresql but nothing changes. More specifically I do this (through pgadmin console):
CREATE DATABASE login;
CREATE USER loginUser WITH PASSWORD 'xxxxxxxxxxxxx';
CREATE TABLE members (
id serial NOT NULL,
username varchar(30) NOT NULL
PRIMARY KEY(id)
)
ALTER USER loginuser WITH SUPERUSER;
ALTER TABLE members OWNER TO loginuser;
GRANT SELECT, UPDATE, INSERT, DELETE ON members TO loginuser;
The query is returned successfully but when I check the table's privileges through the pgadmin gui all of them are selected.
What am I missing?
By default, a table's owner has full privileges on it. If you want "loginuser" to have only select, update, insert, and delete privileges, you would normally revoke all privileges first, then grant just those four.
revoke all on members from loginuser;
grant select, update, insert, delete on members to loginuser;
This will appear to work for you, but it really won't. A database superuser can revoke privileges from a table's owner. But you've made "loginuser" a superuser. Whatever privileges you revoke, "loginuser" can just grant to herself.
You need to think more carefully about what you're trying to accomplish here.
Related
I am experiencing a weird and (to me) inexplicable behaviour related to DEFAULT PRIVILEGES. It seems default privileges cannot be revoked just for a specific schema once they have been granted database-wide.
I am currently testing this with PostgreSQL 10.5 on CentOS.
Let's say there are 3 users:
admin Owner of the database. Used to manipulate the STRUCTURE of the database (CREATE, DROP, TRUNCATE...)
manager Used for DATA manipulation (INSERT, UPDATE, DELETE)
reader Used to read DATA (basically SELECT)
The idea is that:
admin will be the owner of the database and all the objects contained into it
manager will be used for data manipulation across all schemas but public (only user admin can modify data in public schema)
reader will be able to read everything.
To make things easier, this will rely on default privileges, so that newly created objects (schemas, tables, views, functions, etc.) will all have the correct permissions.
This is the first time I am trying something like that instead of a fine-grained permissions policy based on multiple users for all different schemas and apparently this setup should be very straightforward.
It turns out I am missing something.
Here is a simple test script. User admin is the owner of db database and all those commands are issued being connected to it as admin:
-- 1. User manager inherits from user "reader"
GRANT reader TO manager;
-- 2. Allow connections to the database to our users, but not PUBLIC
REVOKE ALL ON DATABASE db FROM PUBLIC;
GRANT CONNECT ON DATABASE db TO reader;
-- 3. Revoke default privileges from PUBLIC
ALTER DEFAULT PRIVILEGES REVOKE ALL ON SCHEMAS FROM PUBLIC;
ALTER DEFAULT PRIVILEGES REVOKE ALL ON TABLES FROM PUBLIC;
ALTER DEFAULT PRIVILEGES REVOKE ALL ON SEQUENCES FROM PUBLIC;
ALTER DEFAULT PRIVILEGES REVOKE ALL ON FUNCTIONS FROM PUBLIC;
-- 4. Grant default reading privileges to user "reader"
ALTER DEFAULT PRIVILEGES GRANT USAGE ON SCHEMAS TO reader;
ALTER DEFAULT PRIVILEGES GRANT SELECT ON TABLES TO reader;
ALTER DEFAULT PRIVILEGES GRANT SELECT ON SEQUENCES TO reader;
ALTER DEFAULT PRIVILEGES GRANT EXECUTE ON FUNCTIONS TO reader;
-- 5. Grant Defauly writing privileges to user "manager"
ALTER DEFAULT PRIVILEGES GRANT INSERT, UPDATE, DELETE ON TABLES TO manager;
ALTER DEFAULT PRIVILEGES GRANT USAGE ON SEQUENCES TO manager;
-- 6. Reinit "public" schema
DROP SCHEMA public;
CREATE SCHEMA public;
-- 7. HERE COMES THE WEIRD STUFF, the two following statements don't have any effect at all
ALTER DEFAULT PRIVILEGES IN SCHEMA public REVOKE INSERT, UPDATE, DELETE ON TABLES FROM manager;
ALTER DEFAULT PRIVILEGES IN SCHEMA public REVOKE USAGE ON SEQUENCES FROM manager;
This can be easily verified like that:
-- Execute as user "admin":
CREATE TABLE public.t (id serial PRIMARY KEY, dummy integer)
-- Execute as user "manager" (it should not be allowed, but it is!)
DELETE FROM public.t;
I know I could circumvent this using some trigger functions, but the point of the question is whether this is something normal and expected, some sort of bug or am I missing something?
I have been thinking about it and the most elegant solution I could come up with relies on an Event Trigger.
Of course it does not answer my question directly, meaning that I am still wondering why default privileges cannot be used like that, but at least this meets the initial requirement of set-and-forget that default privileges would have provided.
Create a function that revokes unwanted privileges and returns an event_trigger:
CREATE FUNCTION reset_privileges() RETURNS event_trigger AS $$
BEGIN
IF EXISTS (SELECT true FROM pg_event_trigger_ddl_commands() WHERE schema_name = 'public') THEN
REVOKE INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public FROM manager;
REVOKE USAGE ON ALL SEQUENCES IN SCHEMA public FROM manager;
END IF;
END;
$$ LANGUAGE plpgsql;
Create an actual EVENT TRIGGER (This requires superuser privileges!):
CREATE EVENT TRIGGER reset_public_schema_privileges
ON ddl_command_end WHEN TAG IN (
'CREATE TABLE',
'CREATE TABLE AS',
'CREATE VIEW',
'CREATE MATERIALIZED VIEW',
'CREATE FUNCTION'
) EXECUTE PROCEDURE reset_privileges();
The function checks whether the newly created object(s) are in the public schema and eventually revokes all the unwanted privileges from the user manager.
It does not even bother to filter those objects, but rather it revokes the privileges for ALL TABLEs, VIEWs and FUNCTIONs in the public schema. Of course it can be easily customised using the object_identity field provided by pg_event_trigger_ddl_commands and a more refined logic inside the function.
According to the manual for ALTER DEFAULT PRIVILEGES:
Default privileges that are specified per-schema are added to whatever the global default privileges are for the particular object type. This means you cannot revoke privileges per-schema if they are granted globally (either by default, or according to a previous ALTER DEFAULT PRIVILEGES command that did not specify a schema). Per-schema REVOKE is only useful to reverse the effects of a previous per-schema GRANT.
(This is even more explicit in the examples given on that manual page.)
So I think what is happening is that in step 5 of your script, you are setting the default privilege to grant DELETE on the tables of all schemas (as a global default):
ALTER DEFAULT PRIVILEGES GRANT INSERT, UPDATE, DELETE ON TABLES TO manager;
But in step 7 you are revoking from the public schema specifically. This revocation has no effect on the global grant, so the DELETE (and other) privileges will still be granted:
ALTER DEFAULT PRIVILEGES IN SCHEMA public REVOKE INSERT, UPDATE, DELETE ON TABLES FROM manager;
I think I would either (a) bite the bullet and add default privileges for each schema (which isn't "fire-and-forget" but is more explicit) or (b) challenge why I need the public schema to exist, aiming to remove it to simplify this situation.
Which tables/columsn are altered for the following queries:
REVOKE ALL PRIVILEGES ON FUNCTION "..."() FROM PUBLIC CASCADE;
-- function_owner can still update the function
GRANT ALL PRIVILEGES ON FUNCTION "..."() TO function_owner CASCADE;
REVOKE ALL PRIVILEGES ON FUNCTION "..."() FROM function_owner CASCADE;
-- function_owner can't update the function.
GRANT ALL PRIVILEGES ON FUNCTION "..."() TO function_owner CASCADE;
-- function_owner can now update the function.
I know that pg_catalog.pg_proc.proacl are altered. Are there any other tables and columns?
pg_proc.proacl is indeed the only column that is modified if you GRANT or REVOKE privileges on a function.
There are two things to keep in mind:
When a function is created, it has the default privileges (PUBLIC and the owner may EXECUTE it) and the proacl column is NULL (this signifies default privileges).
That is why the column is empty in the beginning and contains a value after you REVOKE the privileges for PUBLIC.
If you REVOKE a privilege that hasn't been granted before, nothing happens. Similarly, if you GRANT a privilege that is already granted, nothing happens.
Your GRANT is such a no-operation, because the owner has the EXECUTE privilege by default. You just don't see it before you changed the privilege from the default with your REVOKE.
I have reviewed this well-asked and answered PG permission question, and I use it as a starting point for my question:
https://dba.stackexchange.com/questions/117109/how-to-manage-default-privileges-for-users-on-a-database-vs-schema
How can I observe the differences between:
alter default privileges for role schma_admin
grant select, insert, delete, truncate on tables to schma_mgr;
... and ...
alter default privileges for role schma_mgr -- "admin" and "mgr" are swapped
grant select, insert, delete, truncate on tables to schma_admin;
Many thanks!
After the first statement, all tables newly created by schema_admin will automatically have the specified privileges granted to schema_mgr.
So every table created by schema_admin will have SELECT, INSERT, DELETE and TRUNCATE privileges granted to schema_mgr (in addition to having all privileges granted to the owner).
In the second statement, the roles are reversed, so tables created by schema_mgr will have privileges granted to schema_admin.
Note that this does not affect tables created before the ALTER DEFAULT PRIVILEGES statement.
I have a postgres instance with a user root that has full admin privileges.
I have two databases db1 and db2.
For every database, I would like to have two users dbN_user and dbN_admin. dbN_user will be the used by my application, and dbN_admin will be used for migrations that change the table structure.
No rows are ever deleted by the application, and I would like to enforce that with user privileges.
db1_user should be able to connect to db1, and be able to SELECT, INSERT and UPDATE, but not DELETE.
db1_admin should have additional privileges to DELETE, CREATE TABLE, ALTER TABLE.
What are the SQL statements to set this up?
dbN_admin would be the owner of the objects, so that user would have all privileges automatically.
You need to GRANT the privileges for dbN_user on the tables and other objects themselves, not on the database.
Just add the correct GRANT statements after the CREATE TABLE statements in the SQL script that populates the database.
You need to GRANT the USAGE privilege on the schema that contains the objects to dbN_user as well.
There is the possibility to define default privileges in a database:
ALTER DEFAULT PRIVILEGES FOR dbN_admin
GRANT SELECT, INSERT, UPDATE ON TABLES
TO dbN_user;
This will grant the privileges automatically whenever dbN_admin creates a new table (but it does not affect tables created before the ALTER DEFAULT PRIVILEGES command).
admin:
create user db1_admin;
create schema app_relations;
alter schema app_relations owner to db1_admin;
app:
create user db1_user;
grant CONNECT ON DATABASE db1 to db1_user; --only if you have restricted connections on db previously
grant usage on schema app_relations to db1_user;
grant select,insert,update on all tables in schema app_relations to db1_user;
I have a database with a template_schema.I cloned this template schema and created a database user with password. I need to provide access to cloned schema only, for the created user.
SELECT clone_schema('my_template_schema','john_smith_gmail_com');
CREATE USER john_smith_gmail_com WITH PASSWORD 'mypassword';
Upto this Ok. Then I need to grant access to this user for this cloned schema(john_smith_gmail_com) only
Method :1
I tried to revoke all privileges on all tables of cloned schema(john_smith_gmail_com) for the user and grant select to the user. But my question is, can this user get SELECT access on other schema tables?
REVOKE ALL ON ALL TABLES IN SCHEMA john_smith_gmail_com FROM john_smith_gmail_com;
GRANT SELECT ON ALL TABLES IN SCHEMA john_smith_gmail_com TO john_smith_gmail_com;
Method :2
Create a role with only SELECT access and assign or grant this role to newly created user. If I do this, for which schema I grant access,because I clone schema dynamically?
Which method is best one?
From postgresql version 9.0 and forward, the best way is probably to use ALTER DEFAULT PRIVILEGES.
...the default privileges for any object type normally grant all grantable permissions to the object owner, and may grant some privileges to PUBLIC as well. However, this behavior can be changed by altering the global default privileges with ALTER DEFAULT PRIVILEGES.
So if all users like "john_smith_gmail_com" should only have SELECT access to tables in "their own" schema, after creating the schema and user, you can run:
ALTER DEFAULT PRIVILEGES IN SCHEMA john_smith_gmail_com GRANT SELECT ON TABLES TO john_smith_gmail_com;