-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Description
Description
This is the second in a two ticket series. #5189 is the first ticket. They will be merged sequentially, but both are required for this feature to be exposed to users.
Today users often configure a post_hook to grant permissions on models, seeds, and snapshots:
{{ config(post_hook = 'grant select on {{ this }} to role reporter') }}
These two tickets aim to make it easier to specify grants allowing it to be configured directly both in dbt_project.yml as well as in source files:
# dbt_project.yml
models:
export:
+grants:
select: ['reporter', 'bi']
-- SQL
{{ config(grants = {'select': ['other_user']}) }}
These grant configs will not necessarily look the same for each and every warehouse. The logic to generate the sql from these configs can be overriden by adapters.
Some complexity gets added when you consider that you cannot simply revoke all privileges from a table and apply the configured ones. This is because revoking all may also revoke dbt's ownership of the table, and because some warehouses require explicitly naming the grants to be removed. This implementation reads the grants first, then constructs a minimal revoke and grant statement from the resulting diff.
Implementation
- create a new macro in the global project:
get_show_grant_sql(relation: Relation) -> strthat retrieves grant information for that model. The default implementation should return a string in the form"show grants on table dbt_jcohen.whatever" - create a new macro in the global project:
get_grant_sql(relation: Relation, grant_config: dict) -> strthat creates the warehouse-specific sql from grant portion of the config. Since it will be common, the default implementation should returngrant <privilege> on <relation.type> <relation> to <recipients>. Warehouses that deviate from this can override. Use dispatch pattern (dbt docs) with adefault__to enable this. The macro signature here is designed to accept different shapes of grant configs for each adapter to use whatever best fits the warehouse's permissions system. - create a new macro called
get_revoke_sqlthat takes a relation, and a grant config dict and returns a string in the formf"revoke {grant_config.privilege} on {relation} from {grant_config.recipients}". The grant config will contain multiple priv-recipient mappings. - create a new macro in the global project:
apply_grantswhich takes 3 parameters:revoke: Bool,relation: Relation,grant_config: dictand returnsNone. It callsget_show_grant_sqlto determine what grants are currently applied, and uses grant config to determine what grants need to be revoked, and which grants need to be granted. If therevokeparam isTrue,get_revoke_sqlis called, thenget_grant_sqlwith a new dictionary representing the diff to apply the grants. (seepersist_docsfor an example of similar implementation). This should be overridable by adapters so use the dispatch pattern (dbt docs) with adefault__to enable this. For a complete example see @jtcohen6's comment below. - add a call to
apply_grants(..., revoke=True)in all materializations. This includes incremental models, seeds, and snapshots even though it will usually not be necessary. Users can override if they come across a special case where they need to. - [CT-808] Add "adapter zone" tests for grants #5437
- test that projects can define grants in 1) the dbt_project.yml, 2) models, seeds, and snapshots, and 3) both the dbt_project.yml and models, seeds, and snapshots and those permissions can be read back directly from the postgres warehouse after a run.
- test two subsequent runs (dbt build && dbt build) with: same grants; additional grants in second run; fewer grants in second run. Confirm that the final set of grants matches the final configured set of grants in all cases.
- test a model that has preexisting grants, and does not have grants configured. dbt should leave it be, and not run any show/revoke/grant statements.
Adapters
Links for your convenience. These do not need to be completed to close out the ticket.
- Snowflake: [CT-716] Snowflake: Add Grants to Materializations dbt-snowflake#168
- BigQuery: [CT-717] Add Grants to BigQuery Materializations dbt-bigquery#198
- Spark: [CT-718] Add Grants to Materializations dbt-spark#366
- Postgres: [CT-719] Add Grants to Postgres Materializations #5329
- Redshift: [CT-789] Add support for grant macros dbt-redshift#128