Transaction Control Statements in Procedure Executed as Definer - postgresql

We are just getting started with Postgres and started to explore its features. One of the things we noticed is the limitation to execute a commit within a transaction if the procedure is executed as the definer (with SECURITY DEFINER in the procedure definition).
I saw another post about this and one of the suggested workaround is like to have a wrapper procedure (executed as invoker) where these transaction control statements could be done following a procedure call (executed as definer). What we would like to do though is be able to control it within the transactions in the sub procedure especially if doing autonomous transactions.
Do we know why Postgres has this limitation?
We tried controlling the access privileges on the schema and make sure that only certain users can execute functions or procedures within the schema. We also set session IDs, played around with user/group, ACLs and set table policies for row level security but there is still this question on where to do the commits.
But we expect to be able to control commit and rollback directly within the procedure executed as definer and not from the invoker of the procedure call.

That is explained in ExecuteCallStmt in src/backend/commands/functioncmds.c:
/*
* In security definer procedures, we can't allow transaction commands.
* StartTransaction() insists that the security context stack is empty,
* and AbortTransaction() resets the security context. This could be
* reorganized, but right now it doesn't work.
*/
Indeed, StartTransaction has
/* SecurityRestrictionContext should never be set outside a transaction */
Assert(s->prevSecContext == 0);
This can be traced back to commit eedb068c0a7474fb11d67d03b0a9e1ded5df82c4:
Make standard maintenance operations (including VACUUM, ANALYZE, REINDEX,
and CLUSTER) execute as the table owner rather than the calling user, using
the same privilege-switching mechanism already used for SECURITY DEFINER
functions. The purpose of this change is to ensure that user-defined
functions used in index definitions cannot acquire the privileges of a
superuser account that is performing routine maintenance. While a function
used in an index is supposed to be IMMUTABLE and thus not able to do anything
very interesting, there are several easy ways around that restriction; and
even if we could plug them all, there would remain a risk of reading sensitive
information and broadcasting it through a covert channel such as CPU usage.
To prevent bypassing this security measure, execution of SET SESSION
AUTHORIZATION and SET ROLE is now forbidden within a SECURITY DEFINER context.
Thanks to Itagaki Takahiro for reporting this vulnerability.
Security: CVE-2007-6600
So the intention is to prevent privilege escalation attacks.
You may want to read this mailing list thread that offers more detailed explanations.

Related

Is there a way to protect SQL statements from being altered, while still allowing the person to execute the statement?

I work for a large organization that relies heavily on SQL developer for financial reconciliation. We have only SELECT privileges. Several people have access to the same SQL statements, is there a way to ensure they cant change the code? We need to ensure that people who have access to run our SQL statements to generate a report, do not have the ability to change the code. This forces them to submit change requests if they need the code change, which helps us to create and audit log of the changes made. Our financial audit includes audit of our SQL statements. With too many people making changes it is hard to track/validate the change.
Remove their privileges to SELECT from the tables directly.
Wrap the existing code in a stored procedure (if bind variables are used in the SQL statement then they can be arguments to the stored procedure).
This also allows you to put additional code for verification/auditing inside the stored procedure so that it is automatically run with the query(ies) that the users require.
Create a ROLE and grant the EXECUTE privilege on the stored procedure to that role.
Give that role only to the people who are required to run that stored procedure.

PostgreSQL execute trigger as different user [duplicate]

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?

Modify Trigger in Postgresql

I need to modify a Trigger (which use a particular FUNCTION) already defined and it is being in use. If i modify it using CREATE OR REPLACE FUNCTION, what is the behaviour of Postgres? will it "pause" the old trigger while it is updating the function?. As far as i know, Postgres should execute all the REPLACE FUNCTION in one transaction (so the tables are locked and so the triggers being modify while it is updating, then next transactions locked will use the new FUNCTION not the old one. is it correct?
Yes. According to the documentation:
http://www.postgresql.org/docs/9.0/static/explicit-locking.html
Also, most PostgreSQL commands automatically acquire locks of appropriate modes to ensure that referenced tables are not dropped or modified in incompatible ways while the command executes. (For example, ALTER TABLE cannot safely be executed concurrently with other operations on the same table, so it obtains an exclusive lock on the table to enforce that.)
will it "pause" the old trigger while it is updating the function?
It should continue executing the old trigger functions when calls are in progress (depending on the isolation level, subsequent calls in the same transaction should use the old definition too; I'm not 100% sure the default level would do so, however), block new transactions that try to call the function while it's being updated, and execute the new function once it's replaced.
As far as i know, Postgres should execute all the REPLACE FUNCTION in one transaction (so the tables are locked and so the triggers being modify while it is updating, then next transactions locked will use the new FUNCTION not the old one. is it correct?
Best I'm aware the function associated to the trigger doesn't lock the table when it's updated.
Please take this with a grain of salt, though: the two above statements amount to what I'd intuitively expect mvcc to do, rather than knowing this area of Postgres' source code off the top of my head. (A few core contributors periodically come to SO, and might eventually chime in with a more precise answer.)
Note that this is relatively straightforward to test, that being said: open two psql sessions, open two transactions, and see what happens...

Is there a way to disable updates/deletes but still allow triggers to perform them?

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?

db2 creating proxy user account

SQL server has an option to create proxy user accounts with the statement
CREATE USER proxyUser WITHOUT LOGIN;
I couldn't find much help on internet on getting the db2 (v8) equivalent of this. I'm not sure whether this is possible, if yes please let me know how.
The scenario where i want to use this is as follows.
I have table with ~8 million records which gets updated daily. Before the inserts happen, few records are deleted from the table and the number is ~2 million. Since these deletes need not be logged, we decided on setting off Logging during the deletes. Since our credentials do not have alter table rights, we decided to put the ALTER and DELETE statements in a script and and execute the script using the proxy account irrespective of what user executes the SP.
I foud this article which closely describes the scenario which i described above. The differences are that i need to do this on db2 and i need to do deletes without logging them.
http://www.mssqltips.com/sqlservertip/2583/grant-truncate-table-permissions-in-sql-server-without-alter-table/
Thanks
Arjun
It will work basically in the same manner in DB2, with a few exceptions. Firstly, there's no TRUNCATE TABLE statement in DB2 8.2 (and there's no DB2 version 8 on Linux). Secondly, there are no database users in DB2 -- all users are defined externally in the operating system, so there's no CREATE USER statement either.
All statements in a stored procedure, except dynamic SQL, are executed with the authorization of the procedure creator.
So, using the authorized ID, e.g. the database administrator's ID, create the stored procedure that does what you need (ALTER, DELETE, whatever), then grant the EXECUTE privilege on that procedure to whoever needs to run it.