Basically, I want to be able to use the REVOKE command to disable UPDATE and DELETE, but I still want the triggers on a table to update my rows.
My triggers perform on newly inserted rows, and update a specific field. So I still want this behaviour, but wouldn't they be disabled with REVOKE or with a RULE. (I saw an SO post)
Is there a way to keep using the UPDATE/INSERT commands in TRIGGERS but disabling the rest?
Yes, this is possible.
Triggers are run with the privileges of the trigger function, defaulting to SECURITY INVOKER which means, the trigger function is effectively executed with the privileges of the current_user, in your case the one inserting rows.
If the current user does not have the required privileges for the tables your trigger function operates on, your original operation in the underlying table will error out.
However, you can use SECURITY DEFINER for the trigger function to have this function run with the privileges of the OWNER of the function.
If you have a superuser own the trigger function, it can do everything - which would be a possible security hazard. Consider the instructions in the manual about Writing SECURITY DEFINER Functions Safely.
But it's wiser to make a plain role with just the necessary privileges OWNER of the trigger function. You can even just create a "daemon" role without login, acting as privilege bundle for such operations. You would then grant only the needed privileges (on schemas, tables, sequences ...) to this daemon role. For more sophisticated designs you should bundle privileges in "group roles" (again, no login) and grant these group roles to roles that need it (to the daemon role in this example), effectively making them "member of the group". I do that a lot.
Consider this related answer on dba.SE concerning the privileges on the function itself:
What are the privileges required to execute a trigger function in PostgreSQL 8.4?
Related
Version: PostgresQL 9.6
I create a trigger.
Even if I create a trigger as a superuser, the owner of the database can remove the trigger.
Is it possible to protect the trigger from deletion?
You cannot keep the owner of the table from dropping a trigger on it unless you want to go to the extreme of writing an event trigger for that.
Maybe you should use a different permission concept where you give people only limited privileges if you want to keep them from dropping your triggers. Instead of allowing others to own tables, grant others privileges on the tables.
I want to create a read-only postgres role, and I want the role to be able to use functions that don't modify the database, including functions I might create in the future. Since they don't modify the database (and satisfy the other requirements), I've been marking these functions as STABLE or IMMUTABLE (as appropriate).
Is there a way to grant default execute privileges on STABLE and IMMUTABLE functions to a role? Something similar to alter default privileges in schema public grant select on tables to <role_name>;
I'm using postgresql 9.6.
You can't do it that way.
You could probably write an event trigger to do it by examining the definition of the function in the catalogs.
Note that volatile functions can be read-only too, and stable functions can have side effects. So I don't think trying to do this based on volatility is correct anyway.
I want create users that only can execute functions from one database. Not view source functions, procedures, select, etc of any database.
Thanks.
This should do it:
Allow the user to connect to only the correct database, either with permissions on the database object (you have to REVOKE the CONNECT privilege granted to PUBLIC by default first) or with suitable entries in pg_hba.conf.
In the one database where the user can connect, it should have USAGE privilege on the schemas that contain the functions.
Create functions with SECURITY INVOKER that belong to a user that has the rights to access the required objects.
REVOKE EXECUTE on all functions from PUBLIC and GRANT it to the user as required.
There is no supported way in PostgreSQL to keep a user that can log on from seeing the source code of functions. You can try to REVOKE SELECT ON pg_proc FROM PUBLIC, but don't be surprised if you get problems with client programs like pgAdmin or psql.
I have a Postgresql database for a web application. The database is owned by a particular user on the system, let's say foouser. As the owner, this user has full permissions on the database.
The server also has another user, let's say webappuser, which is the user under which the application server runs. Instead of specifying a username and password in the web application's config file, I want to use "peer" authentication. I have gotten the authentication to work properly, but I ran into the following issue.
When I created the webappuser role in Postgresql, I granted it LOGIN permission as well as GRANT ALL ON DATABASE foo TO webappuser; and within the database GRANT ALL ON SCHEMA public TO webappuser;.
The issue that I am having is with the table permissions. Unlike MySQL which allows access by default to all tables if you have access to the database (a reasonable assumption in my opinion), Postgresql denies access to all of the tables even though permission has been given on the schema and the database. In order to get around this, I have to explicitly grant permissions on all new tables, views, procedures, etc. that I create using GRANT ALL ON TABLE table_name TO webappuser; (and similarly for views, etc.).
It ends up that any time I run a database migration, I have to add the permissions to the database for the new tables that were created. The problem is that I can't add this permission information to the migrations themselves because developer machines don't have that additional user. In any case, that really looks like the wrong way of doing things.
How can I allow access to the database tables from this additional user without needing manual intervention every time a table, view, procedure, etc. is created?
BONUS POINTS: Is there a way to restrict the user's permission to only CRUD operations instead of full permissions and still do the whole thing automatically?
Without experience with the specifics of Laravel migrations: When you do migrations on the same server there should be no problem, so long as the permissions are also migrated, because the webappuser is available cluster-wide.
When migrating to a different server you need to create the user on that new server and set the permissions for all migrated objects. You basically have two ways to do that.
The first is to set default privileges on the tables in the schema before you migrate or GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA sch_name TO webappuser after the migration. Default privileges are set with:
ALTER DEFAULT PRIVILEGES IN SCHEMA sch_name
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO webappuser;
Both commands are fully SQL-standard compliant so you should have no problems across compliant architectures.
Keep in mind that any other tables created in the same schema will also have privileges set for webappuser. Setting privileges this way for an "untrusted" user (the person using the web application) is not recommended in a production environment because of potential privilege leaks; in a development environment it may be acceptable.
The second - which I would favour personally - is to write a stored procedure that sets the appropriate permissions. Do the migration, run the stored procedure once and you should be up-and-running. This gives you more control over the permission granting. The procedure could be something like:
CREATE FUNCTION grant_webapp_privileges() RETURNS void AS $$
-- Create the webappuser, if necessary
CREATE ROLE webappuser LOGIN;
-- Grant privileges on all required objects
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE table1 TO webappuser;
...
$$ LANGUAGE SQL;
On the master database you simply need to keep the stored procedure up-to-date when you create or drop new relations. If Laravel supports insertion of code blocks not in the schema you are migrating, you can make the above procedure an anonymous code block that gets executed after the migration.
(As an aside, I NEVER give webappuser-like roles CRUD access. Instead I always provide access through views that hide some of the underlying data model specifics, such as a person having an address, contact_information and other details; the view serves it all up in one big row. That way you can easily change the underlying relations and update the view, rather than having to tweak your web application. Same principle really as OOP and easier to manage privileges.)
Basically, I want to be able to use the REVOKE command to disable UPDATE and DELETE, but I still want the triggers on a table to update my rows.
My triggers perform on newly inserted rows, and update a specific field. So I still want this behaviour, but wouldn't they be disabled with REVOKE or with a RULE. (I saw an SO post)
Is there a way to keep using the UPDATE/INSERT commands in TRIGGERS but disabling the rest?
Yes, this is possible.
Triggers are run with the privileges of the trigger function, defaulting to SECURITY INVOKER which means, the trigger function is effectively executed with the privileges of the current_user, in your case the one inserting rows.
If the current user does not have the required privileges for the tables your trigger function operates on, your original operation in the underlying table will error out.
However, you can use SECURITY DEFINER for the trigger function to have this function run with the privileges of the OWNER of the function.
If you have a superuser own the trigger function, it can do everything - which would be a possible security hazard. Consider the instructions in the manual about Writing SECURITY DEFINER Functions Safely.
But it's wiser to make a plain role with just the necessary privileges OWNER of the trigger function. You can even just create a "daemon" role without login, acting as privilege bundle for such operations. You would then grant only the needed privileges (on schemas, tables, sequences ...) to this daemon role. For more sophisticated designs you should bundle privileges in "group roles" (again, no login) and grant these group roles to roles that need it (to the daemon role in this example), effectively making them "member of the group". I do that a lot.
Consider this related answer on dba.SE concerning the privileges on the function itself:
What are the privileges required to execute a trigger function in PostgreSQL 8.4?