I have been tasked to host HTML & PHP files of a website on one virtual machine and to set up a Postgresql database on another virtual machine.
I recently installed Postgresql and have been using the official Postgresql Documentation to learn how to create databases, create user and grant & revoke rights.
After having created a database named mfc_dst, I was ordered to create 4 differents users and this is where I have a problem :
-The first user has to be named admin and must be the only other user than the pre-existing user named postgres to have unlimited rights.
-The second (named cfc) and third user (named sec) must only have the SELECT and UPDATE privileges on all tables of the mfc_dst database.
-And the fourth/last user (named prof) must only be able to view a table named devoir from the database named mfc_dst.
To accomplish this, I used 2 different scripts :
CREATEandGRANT.sql
REVOKE ALL ON ALL TABLES IN SCHEMA public TO cfc;
REVOKE ALL ON ALL TABLES IN SCHEMA public TO sec;
REVOKE ALL ON ALL TABLES IN SCHEMA public TO prof;
GRANT CONNECT ON DATABASE mfc_dst TO admin;
GRANT CONNECT ON DATABASE mfc_dst TO cfc;
GRANT CONNECT ON DATABASE mfc_dst TO sec;
GRANT CONNECT ON DATABASE mfc_dst TO prof;
GRANT SELECT,UPDATE
ON ALL TABLES IN SCHEMA public
TO cfc;
GRANT SELECT,UPDATE
ON ALL TABLES IN SCHEMA public
TO sec;
GRANT SELECT ON devoir TO prof;
and this other one :
REVOKE.sql
REVOKE ALL ON TABLE professeur FROM PUBLIC;
REVOKE ALL ON TABLE reserver FROM PUBLIC;
REVOKE ALL ON TABLE salle FROM PUBLIC;
REVOKE ALL ON TABLE semaine FROM PUBLIC;
REVOKE ALL ON TABLE surveiller FROM PUBLIC;
Thanks to these 2 scripts, I was able to prevent the user named prof from seeing other tables, but the problem I have is that the users named cfc,sec and prof are still all three able to create tables and to drop them.
Is it possible to know how to prevent them from doing this and if possible, in the future, prevent newly created users from having such rights/privileges ?
Thank you in advance
All Postgres users implicitly are also automatically members of the public role, which grants them all permissions on the public schema. You can remove permissions from the public role with
revoke all on database mfc_dst from public;
revoke all on schema public from public;
Additionally, consider defining a new schema for your data tables, so that you can issue grant statements without having to deal further with the public role. If you do this, you can also set the search path to include your custom schema and to exclude the public schema.
Also, you might want to create a group role for the cfc and sec users and assign permissions to that role, rather than to the users individually. This will make future maintenance easier.
Related
I have a user db_owner who is owner to my database called 'Sales'.
Now i have to create two groups(sales_ro and sales_riu) and then i will add users to this groups.
sales_ro group should inherit(from db_owner) read access on tables and execute on functions in Sales db
sales_riu group should inherit(from db_owner) insert and update access on tables and execute on functions in Sales db.
can we create such two groups in Postgres ?
You don't need to create groups to achieve this. You can just create Roles and assign them to the users you want. For example:
CREATE ROLE sales_ro;
CREATE ROLE sales_riu;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO sales_ro;
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public TO sales_ro;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO sales_ro;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT EXECUTE ON FUNCTIONS TO sales_ro;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT,INSERT,UPDATE ON TABLES TO sales_riu;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT EXECUTE ON FUNCTIONS TO sales_riu;
After that just grant role to expected users:
GRANT sales_ro TO your_user_1;
GRANT sales_riu TO your_user_2;
Please refer link 1 and link 2 to know more about ALTER DEFAULT PRIVILEGES and CREATE ROLE respectively.
Quoting below points from above links:
CREATE ROLE adds a new role to a PostgreSQL database cluster. A role
is an entity that can own database objects and have database
privileges; a role can be considered a “user”, a “group”, or both
depending on how it is used.
A role having the LOGIN attribute can be thought of as a user. Roles
without this attribute are useful for managing database privileges
I'm moving from MySQL to PostgreSQL and have hit a wall with user privileges. I am used to assigning a user all privileges to all tables of a database with the following command:
# MySQL
grant all privileges on mydatabase.* to 'myuser'#'localhost' identified by 'mypassword';
It appears to me that the PostgreSQL 9.x solution involves assigning privileges to a "schema", but the effort required of me to figure out exactly what SQL to issue is proving excessive. I know that a few more hours of research will yield an answer, but I think everyone moving from MySQL to PostgreSQL could benefit from having at least one page on the web that provides a simple and complete recipe. This is the only command I have ever needed to issue for users. I'd rather not have to issue a command for every new table.
I don't know what scenarios have to be handled differently in PostgreSQL, so I'll list some of the scenarios that I have typically had to handle in the past. Assume that we only mean to modify privileges to a single database that has already been created.
(1a) Not all of the tables have been created yet, or (1b) the tables have already been created.
(2a) The user has not yet been created, or (2b) the user has already been created.
(3a) Privileges have not yet been assigned to the user, or (3b) privileges were previously assigned to the user.
(4a) The user only needs to insert, update, select, and delete rows, or (4b) the user also needs to be able to create and delete tables.
I have seen answers that grant all privileges to all databases, but that's not what I want here. Please, I am looking for a simple recipe, although I wouldn't mind an explanation as well.
I don't want to grant rights to all users and all databases, as seems to be the conventional shortcut, because that approach compromises all databases when any one user is compromised. I host multiple database clients and assign each client a different login.
It looks like I also need the USAGE privilege to get the increasing values of a serial column, but I have to grant it on some sort of sequence. My problem got more complex.
Basic concept in Postgres
Roles are global objects that can access all databases in a db cluster - given the required privileges.
A cluster holds many databases, which hold many schemas. Schemas (even with the same name) in different DBs are unrelated. Granting privileges for a schema only applies to this particular schema in the current DB (the current DB at the time of granting).
Every database starts with a schema public by default. That's a convention, and many settings start with it. Other than that, the schema public is just a schema like any other.
Coming from MySQL, you may want to start with a single schema public, effectively ignoring the schema layer completely. I am using dozens of schema per database regularly.
Schemas are a bit (but not completely) like directories in the file system.
Once you make use of multiple schemas, be sure to understand search_path setting:
How does the search_path influence identifier resolution and the "current schema"
Default privileges
Per documentation on GRANT:
PostgreSQL grants default privileges on some types of objects to
PUBLIC. No privileges are granted to PUBLIC by default on tables,
columns, schemas or tablespaces. For other types, the default
privileges granted to PUBLIC are as follows: CONNECT and CREATE TEMP TABLE
for databases; EXECUTE privilege for functions; and USAGE privilege for languages.
All of these defaults can be changed with ALTER DEFAULT PRIVILEGES:
Grant all on a specific schema in the db to a group role in PostgreSQL
Group role
Like #Craig commented, it's best to GRANT privileges to a group role and then make a specific user member of that role (GRANT the group role to the user role). This way it is simpler to deal out and revoke bundles of privileges needed for certain tasks.
A group role is just another role without login. Add a login to transform it into a user role. More:
Why did PostgreSQL merge users and groups into roles?
Predefined roles
Update: Postgres 14 or later adds the new predefined roles (formally "default roles") pg_read_all_data and pg_write_all_data to simplify some of the below. See:
Grant access to all tables of a database
Recipe
Say, we have a new database mydb, a group mygrp, and a user myusr ...
While connected to the database in question as superuser (postgres for instance):
REVOKE ALL ON DATABASE mydb FROM public; -- shut out the general public
GRANT CONNECT ON DATABASE mydb TO mygrp; -- since we revoked from public
GRANT USAGE ON SCHEMA public TO mygrp;
To assign "a user all privileges to all tables" like you wrote (I might be more restrictive):
GRANT ALL ON ALL TABLES IN SCHEMA public TO mygrp;
GRANT ALL ON ALL SEQUENCES IN SCHEMA public TO mygrp; -- don't forget those
To set default privileges for future objects, run for every role that creates objects in this schema:
ALTER DEFAULT PRIVILEGES FOR ROLE myusr IN SCHEMA public
GRANT ALL ON TABLES TO mygrp;
ALTER DEFAULT PRIVILEGES FOR ROLE myusr IN SCHEMA public
GRANT ALL ON SEQUENCES TO mygrp;
-- more roles?
Now, grant the group to the user:
GRANT mygrp TO myusr;
Related answer:
PostgreSQL - DB user should only be allowed to call functions
Alternative (non-standard) setting
Coming from MySQL, and since you want to keep privileges on databases separated, you might like this non-standard setting db_user_namespace. Per documentation:
This parameter enables per-database user names. It is off by default.
Read the manual carefully. I don't use this setting. It does not void the above.
Maybe you could give me an example that grants a specific user
select/insert/update/delete on all tables -- those existing and not
yet created -- of a specific database?
What you call a database in MySQL more closely resembles a PostgreSQL schema than a PostgreSQL database.
Connect to database "test" as a superuser. Here that's
$ psql -U postgres test
Change the default privileges for the existing user "tester".
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT INSERT, SELECT, UPDATE, DELETE ON TABLES
TO tester;
Changing default privileges has no effect on existing tables. That's by design. For existing tables, use standard GRANT and REVOKE syntax.
You can't assign privileges for a user that doesn't exist.
You can forget about the schema if you only use PUBLIC.
Then you do something like this: (see doc here)
GRANT { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER }
[, ...] | ALL [ PRIVILEGES ] }
ON { [ TABLE ] table_name [, ...]
| ALL TABLES IN SCHEMA schema_name [, ...] }
TO { [ GROUP ] role_name | PUBLIC } [, ...] [ WITH GRANT OPTION ]
I don't want to grant rights to all users and all databases, as seems to be the conventional shortcut, because that approach compromises all databases when any one user is compromised. I host multiple database clients and assign each client a different login.
OK. When you assign tables to the correct role, the privileges granted will be role-specific and not to all users! Then you can decide who to give roles to.
Create a role for each database. A role can hold many users.
Then assign a client-username to the correct role.
Also assign your-username to each role if needed.
(1a) Not all of the tables have been created yet, or (1b) the tables have already been created.
OK. You can create tables later.
When you are ready, assign tables to the correct client role.
CREATE TABLE tablename();
CREATE ROLE rolename;
ALTER TABLE tablename OWNER TO rolename;
(2a) The user has not yet been created, or (2b) the user has already been created.
OK. Create usernames when you are ready. If your client needs more than one username simply create a second client-username.
CREATE USER username1;
CREATE USER username2;
(3a) Privileges have not yet been assigned to the user, or (3b) privileges were previously assigned to the user.
OK. When you are ready to give privileges, create the user and assign the correct role to her.
Use GRANT-TO command to assign roles to users.
GRANT rolename TO username1;
GRANT rolename TO username2;
(4a) The user only needs to insert, update, select, and delete rows, or (4b) the user also needs to be able to create and delete tables.
OK. You run these commands to add permissions to your users.
GRANT SELECT, UPDATE, INSERT, DELETE ON dbname TO role-or-user-name;
ALTER USER username1 CREATEDB;
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.
My goal is to only enable a specific user to execute functions in a specific schema, list the functions available by name but not see the source code of the function or list other schema.
It is possible to achieve the above without the ability to list the available function names via carrying out the following:
First create a test user role:
CREATE ROLE test_user WITH LOGIN PASSWORD 'secret';
Now revoke all permissions from the public on all schemas:
REVOKE ALL PRIVILEGES ON DATABASE test_db FROM PUBLIC;
REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA public FROM PUBLIC;
REVOKE ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA public FROM PUBLIC;
REVOKE ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public FROM PUBLIC;
REVOKE ALL ON SCHEMA public FROM PUBLIC;
REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA function_schema FROM PUBLIC;
REVOKE ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA function_schema FROM PUBLIC;
REVOKE ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA function_schema FROM PUBLIC;
REVOKE ALL ON SCHEMA function_schema FROM PUBLIC;
REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA table_schema FROM PUBLIC;
REVOKE ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA table_schema FROM PUBLIC;
REVOKE ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA table_schema FROM PUBLIC;
REVOKE ALL ON SCHEMA table_schema FROM PUBLIC;
Setup restricted access for test user:
GRANT CONNECT ON DATABASE test_db TO test_user;
GRANT USAGE ON SCHEMA function_schema TO test_user;
REVOKE ALL ON SCHEMA public FROM test_user;
REVOKE ALL ON SCHEMA table_schema FROM test_user;
GRANT EXECUTE ON FUNCTION function_schema.function1() TO test_user;
GRANT EXECUTE ON FUNCTION function_schema.function2(integer) TO test_user;
Now to hid the schema structure and code form the test users and public:
REVOKE SELECT ON TABLE pg_proc FROM public;
REVOKE SELECT ON TABLE pg_proc FROM test_user;
This all works well, the test user can execute the functions but they can't see the code inside the functions, nor can they see the schema and table structure.
--
I'd like to allow the test user to now see the functions by name in the test_functions schema.I've tried the following according to GRANT Postgresql 9.3 (this is granting select on every column in pg_proc):
GRANT SELECT (proname,pronamespace,proowner,prolang,procost,prorows,
provariadic,protransform,proisagg,proiswindow,prosecdef,proleakproof,
proisstrict,proretset,provolatile,pronargs,pronargdefaults,prorettype,
proargtypes,proallargtypes,proargmodes,proargnames,proargdefaults,prosrc,
probin,proconfig,proacl) ON TABLE pg_proc TO test_user;
The result here is that the test user does not get all the same select permissions as if they had access to the whole table. They still can't see the function names.
Another test was to do the reverse, grant select to the table then revoke select on all columns accouding to REVOKE postgresql 9.3:
GRANT SELECT ON TABLE pg_proc TO test_user;
REVOKE SELECT (proname,pronamespace,proowner,prolang,procost,prorows,
provariadic,protransform,proisagg,proiswindow,prosecdef,proleakproof,
proisstrict,proretset,provolatile,pronargs,pronargdefaults,prorettype,
proargtypes,proallargtypes,proargmodes,proargnames,proargdefaults,prosrc,
probin,proconfig,proacl) ON TABLE pg_proc FROM test_user;
Again this doesn't work, they now can see all schemas, code and tables (on allowed schemas).
It appears that the grant/revoke on specific columns doesn't work the way the documentation suggests.
Searching extensively yielded How to restrict access to code in a function wich suggests revoking access to only the pg_proc.prosrc column which clearly doesn't work from the tests above.
I'm using postgresql 9.3
Please feel free to suggest any other solution that comes to mind.
Working with column permissions should work but is probably not the best approach here. Maintaining privileges in this way is rather burdensome in PostgreSQL. Using this approach you have to set and track your security policy for individual users on all affected system catalog relations. Just imagine having to update your security policy when you have more than a few users.
Rather than applying detailed security roles on relations, I suggest that you lock everything in the system catalogs down (as you did) and then create views to selectively expose parts of the system catalogs (this is already the case in the standard setup, but apparently not strict enough for your case). GRANT SELECT on those views to a group role and then grant that group role to login roles (which should have the INHERIT property). This way it is much easier to track what you have done and to update your security policy as all policy is contained in a set of views (content) and group roles (accessibility). If you are using PostgreSQL-9.2+ check out the with security-barrier option on the views as this will prevent optimizer-spoofing by malicious users.
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).