Open alexanderfreller opened 4 months ago
@alexanderfreller , your issue is addressed in V 1.8.7 release. The way table is renamed changed in v.1.8.7. You can use pre-hooks to drop the objects and use post hooks to create those objects and required permissions. I am attaching a screenshot that shows the difference between v.1.7.4 and v.1.8.7.
Please note that this change is introduced only in v.1.8.7.
Thank you for the update, I can indeed now use pre-hooks to drop any security policies attached to a table and use post-hooks to recreate the security policies. Unfortunately when I do that there is a short time were the old table still exists but the security policy is already deleted. Therefore this approach leaks data, if a user queries the table after the security policy is deleted and before the table is deleted (or renamed).
My config looks roughly like this:
models:
dbt_assets:
qlik_views:
+schema: qlik_views
+materialized: table
qlik_views__company:
+pre-hook:
- |
{% do drop_security_policies_of_current_relation() %}
+post-hook:
- |
{% do setup_row_level_security([
{"principal": "my_entra_id_group", "condition": "@my_column= 'some value'"},
]) %}
drop_security_policies_of_current_relation
is a macro that gets all the security polices that apply to the current relation and drops them.
setup_row_level_security
is a macro that creates a function that filters the table rows based on a user or group and sets it as a filter predictate on the current table.
Therefore the questions are:
Why is there a period of time where the security policy does not apply? My understanding was that pre- and post-hooks and creation of the new table happen inside of the same transaction.
Can this be changed such that there is no data leak? Otherwise this feature cannot be used to handle security relevant tasks.
@alexanderfreller, I spoke to DBT team, and I was informed that pre-hooks, model and post-hooks are executed in different transaction context. And by default, auto commit is turned on in Fabric and will anyway run each statement in separate transaction context.
However, you can run pre-hook, model and post hook macros wrapped up with BEGIN TRAN and COMMIT statements. You can run an explicit multi statement transaction and auto commit will be turned off during this transaction and will turn on after a commit/rollback statement is executed.
Would this work?
Ideally it should be possible for the adapter to wrap each model as an explicit transaction, and I am trying to figure out that option with DBT core team as I adding my comment. Hoping to provide an answer for you.
I tried to manually start the transaction in the pre-hook and commit it in the post hook as follows:
models:
dbt_assets:
qlik_views:
+schema: qlik_views
+materialized: table
qlik_views__company:
+pre-hook:
- BEGIN TRANSACTION
- |
{% do drop_security_policies_of_current_relation() %}
+post-hook:
- |
{% do setup_row_level_security([
{"principal": "my_entry_group", "condition": "@some_column = 'somevalue'"},
]) %}
- COMMIT
Is that what you meant?
This failed with the following error:
('42000', '[42000] [Microsoft][ODBC Driver 18 for SQL Server][SQL Server]Transaction failed because this DDL statement is not allowed inside a snapshot isolation transaction.
Since metadata is not versioned, a metadata change can lead to inconsistency if mixed within snapshot isolation. (3964) (SQLExecDirectW)')
From the debug log I can see that the error happens when CREATE SECURITY POLICY ...
is executed inside the setup_row_level_security
.
I tried running ALTER DATABASE {{this.database}} SET ALLOW_SNAPSHOT_ISOLATION OFF
as a pre-hook as well but that also does not work: ('42000', '[42000] [Microsoft][ODBC Driver 18 for SQL Server][SQL Server]ALLOW_SNAPSHOT_ISOLATION is not supported for ALTER DATABASE. (15869) (SQLExecDirectW)')
Do you know how to get around this issue? Did you get a reply from the DBT team?
I would like to manage row-level security with dbt. The goal is to manage it in a way that is scalable and can be integrated with the git review process, even with many users. Unfortunately dbt cannot operate on tables that have a security policy attached.
Therefore the main question is: What is the recommended way to handle row-level security in Fabric with dbt?
Here is my attempt:
This is based on the
dimension_employee
example data available in Fabric and a single model:test_employee.sql
:Security policies can be created by using dbt
post-hook
s. This the the fulldbt_project.yml
:This successfully creates the function, security policy and grant when it is first executed. However when it is executed the second time this happens:
This happens because tables with enforced security polices cannot be renamed. It seems there is no way to drop a security policy before dbt tries to rename the table.
Even with
pre-hook
s it is not possible since they are only executed after renaming the tables. This was the unsuccessful attempt to drop the security policies:Workaround:
One possible workaround would be to define a dbt operation that first drops all grants and then removes all security policies and functions. For example:
This works but has some significant drawbacks:
This workaround could be improved by not hard-coding the objects to be dropped but instead loading the from the system tables. For example, loading the list of grants from the system table and dropping them all. This would make the solution a bit more robust but would not eliminate the drawbacks stated above.
Do you have any ideas to overcome these issues? What is the best way to handle row-level security in dbt-fabric?