Перейти к основному содержимому

Обновление наших рекомендаций по разрешениям: grants как конфигурации в dbt Core v1.2

· 7 мин. чтения
Jeremy Cohen
Doug Beatty

Если вам нужно было предоставить доступ к модели dbt с 2019 года по сегодняшний день, есть большая вероятность, что вы наткнулись на пост "Точные операторы grant, которые мы используем в проекте dbt" на Discourse. В нем объяснялись варианты для покрытия двух дополнительных возможностей:

  1. запрос отношений через привилегию "select"
  2. использование схемы, в которой находятся эти отношения, через привилегию "usage"

Решение тогда

До dbt Core v1.2 мы предлагали три возможных подхода (каждый из которых имел предостережения и компромиссы):

  1. Использование хуков on-run-end для grant select on all таблиц/представлений, которые только что построил dbt
  2. Использование post-hook для предоставления select на модели сразу после ее построения
  3. Использование либо стандартных грантов (будущие гранты в Snowflake), либо комбинации post-hooks и on-run-end хуков

Эти варианты были передовыми... до сегодняшнего дня!

Что изменилось?

В версии v1.2 мы представили конфигурацию grants, которая работает очень похоже на post-hook, с двумя ключевыми отличиями:

  • Вы настраиваете grants как структурированный словарь, а не пишете весь SQL самостоятельно
  • dbt выберет наиболее эффективный путь для применения этих грантов

Почему grants лучше, чем хуки

Во-первых, хуки сложны! Особенно эта путаница с вложенными фигурными скобками.

Проблема тогда

Предположим, вы работали над инкрементальной моделью. Ранее вы предоставили доступ к этой инкрементальной модели напрямую reporter, чтобы люди могли запрашивать ее далее:

-- models/my_incremental_model.sql

{{ config(
materialized = 'incremental',
post_hook = ["grant select on {{ this }} to reporter"]
) }}

select ...

Со временем эта модель взяла на себя все больше и больше обязанностей, и вы решили переработать инкрементальную модель, чтобы она питала серию специализированных представлений. Заботливо, вы также удалили post_hook, который предоставлял прямой доступ к инкрементальной модели:

-- models/my_incremental_model.sql

{{ config(materialized = 'incremental') }}

select ...

Проблема? Пока вы не выполните --full-refresh, ваша инкрементальная модель все еще предоставлена роли reporter!

Решение сегодня

Новая реализация grants в dbt учитывает это. Она знает, переносятся ли гранты, когда модель запускается повторно, в зависимости от ее материализации и вашей базы данных. Она компенсирует разницу между существующими грантами и теми, которые вы действительно хотите.

Попробуйте!


-- models/my_incremental_model.sql

{{ config(
materialized = 'incremental',
grants = {'select': ['another_user']}
) }}

select ...

Запустите это, убедитесь, что another_user может выбрать вашу модель. Затем измените вашу модель и запустите ее снова:

-- models/my_incremental_model.sql

{{ config(
materialized = 'incremental',
grants = {'select': []}
) }}

select ...

Если вы проверите свою базу данных, вы должны увидеть, что никто не может выбрать из инкрементальной модели. Вы также можете увидеть в журналах уровня отладки, что dbt выполнил оператор revoke.

(Обратите внимание, что если grants отсутствует или установлен в {}, dbt поймет, что вы не хотите, чтобы он управлял грантами для этой таблицы. Поэтому лучше явно указать привилегию и то, что вы хотите, чтобы никто ее не имел!)

Отлично! Теперь, когда вы используете функцию grants в dbt v1.2, вы только что уделили этому больше внимания, чем когда-либо потребуется снова 😎

Есть ли еще место для хуков?

Да, конечно! Некоторые области, которые выделяются:

Предоставление разрешений на другие типы объектов

На данный момент все еще необходимо предоставлять usage на схемы пользователям, которым нужно будет выбирать объекты в этих схемах. Хотя dbt создает схемы в начале запусков, на самом деле нет способа настроить схемы как их собственные объекты в dbt.

Вот несколько способов, как вы можете подойти к этому:

  • Вариант A -- простой и знакомый -- хуки на помощь
  • Вариант B -- слишком хитро -- использовать граф dbt, чтобы определить, какие схемы нуждаются в "usage"

Вариант A: простой и знакомый

on-run-end:
# лучше как макрос
- "{% for schema in schemas %}grant usage on schema {{ schema }} to reporter;{% endfor %}"

Плюсы: Коротко, ясно, по делу.

Минусы: нам нужно повторить тот же список ролей здесь, который мы указали в нашей конфигурации grants.

Вариант B: Слишком хитро

Теперь, когда grants является реальной конфигурацией в dbt, доступной через метаданные dbt, вы можете делать с ней всевозможные интересные вещи. Например, определить, какие схемы имеют хотя бы один объект, предоставляющий select роли, и затем предоставить usage на эту схему этой роли!

-- macros/operations/reporting_grants.sql
{% macro grant_usage_on_schemas_where_select() %}
/*
Примечание: Это только псевдокод, для демонстрационных целей
Для каждой роли, которая может получить доступ хотя бы к одному объекту в схеме,
предоставить 'usage' на эту схему этой роли.
Таким образом, пользователи с этой ролью могут выполнять метаданные запросы, показывающие объекты
в этой схеме (обычная потребность для BI-инструментов)
*/
{% set schema_grants = {} %}
{% if execute %}
{% for node in graph.nodes.values() %}
{% set grants = node.config.get('grants') %}
{% set select_roles = grants['select'] if grants else [] %}
{% if select_roles %}
{% set database_schema = node.database ~ "." ~ node.schema %}
{% if database_schema in database_schemas %}
{% do schema_grants[database_schema].add(select_roles) %}
{% else %}
{% do schema_grants.update({database_schema: set(select_roles)}) %}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% set grant_list %}
{% for schema in schema_grants %}
{% for role in schema_grants[schema] %}
grant usage on schema {{ schema }} to {{ role }};
{% endfor %}
{% endfor %}
{% endset %}
{{ return(grant_list) }}
{% endmacro %}

Это, конечно, слишком хитро -- но вы поняли идею и получили иллюстрацию того, что возможно!

Вы даже можете сделать это в начале запуска, сразу после того, как dbt создаст свои схемы, а не ждать до конца. (Хотя это не большая проблема ждать.)

on-run-start:
- {{ grant_usage_on_schemas_where_select() }}

Расширенные разрешения (или другие операции)

Хотите ограничить доступ к определенным строкам в таблице для определенных пользователей? Или динамически маскировать значения столбцов в зависимости от того, кто запрашивает?

Подход варьируется в зависимости от базы данных: в Snowflake вам все еще понадобится post-hook, чтобы применить политику доступа к строкам или политику маскирования столбцов к вашей таблице, тогда как в Databricks вы бы использовали функции динамического представления.

Хорошо иметь хуки и операции как метод использования передовых возможностей базы данных. Любые случаи, которые станут широко и явно продемонстрированной потребностью, могут быть улучшены путем их интеграции в dbt-core.

Приложение

Предостережения и компромиссы оригинальных рекомендаций

on-run-end хуки:

в период времени между запуском модели и концом запуска никто не сможет запросить эту модель, вместо этого они получат ошибку "permission denied". Это создает простой в вашем BI-инструменте."

привилегия manage grants:

Стоит отметить, что эта привилегия является глобальной привилегией – теперь любой, использующий роль transformer, может изменять гранты на любом объекте, как будто они являются владельцем объекта. Решать вам, комфортно ли вам с этим! Если нет, вы можете использовать комбинацию post-hooks и on-run-end хуков вместо этого 🙂"

Основные проблемы:

  • Даже если вы написали самый DRY код, который могли, все равно существуют тысячи проектов, которые все написали одни и те же DCL операторы, обернутые в одни и те же макросы.
  • Стандартные + будущие гранты — наша оригинальная рекомендация, еще в 2019 году — сложны. Они часто требуют дополнительных разрешений (статус суперпользователя!), они вступают в силу автоматически и не подходят для многих организаций с более строгими политиками безопасности.

Проблемы, связанные с хуками

Это всего лишь образец проблем, которые мы видели:

Comments

Loading