Динамические маскирующие маски Snowflake базовая таблица: производные таблицы не маскируются, и представления становятся пустыми?

#snowflake-cloud-data-platform #snowflake-data-masking

#snowflake-cloud-data-platform #snowflake-маскирование данных

Вопрос:

У меня есть необработанная таблица, в которой есть столбец variant данных json. Есть несколько обычных представлений (не материализованных представлений), и таблицы создаются с использованием событий json из необработанной таблицы.

После применения политики маскирования с использованием UDF к столбцу variant необработанной таблицы, когда роль является bi_analyst , я обнаружил две проблемы:

  1. Таблицы, производные от базовой таблицы, не маскируются с помощью bi_analyst роли;
  2. Представления, полученные с использованием базовой таблицы, становятся пустыми с bi_analyst ролью;

Кто-нибудь знает, почему это произошло? эта функция динамической маскировки не поддерживает представления в базовой таблице?

Что я хотел бы сделать, так это замаскировать базовые данные, и все таблицы и представления, исходящие из них, также маскируются указанной ролью. С этими таблицами легко работать, поскольку я могу просто применить политику маскирования и к ним.

Однако я понятия не имею об этих представлениях. Как я могу по-прежнему получать доступ к представлениям с ролью, которая должна видеть данные, но не чувствительные столбцы?

UDF является:

 -- JavaScript UDF to mask pii data --
use role ACCOUNTADMIN;

CREATE OR REPLACE FUNCTION full_address_masking(V variant)
  RETURNS variant
  LANGUAGE JAVASCRIPT
  AS
  $$
    if ("detail" in V) {
        if ("latitude" in V.detail) {
            V.detail.latitude = "******";
        }
        if ("longitude" in V.detail) {
            V.detail.longitude = "******";
        }
        if ("customerAddress" in V.detail) {
            V.detail.customerAddress = "******";
        }
    }

    return V;
  $$;
  

Политика маскирования заключается:

 -- Create a masking policy using JavaScript UDF --
create or replace masking policy json_address_mask as (val variant) returns variant ->
    CASE
      WHEN current_role() IN ('ACCOUNTADMIN') THEN val
      WHEN current_role() IN ('BI_ANALYST') THEN full_address_masking(val)
    ELSE full_address_masking(val)
    END;
  

Команда sql для установки политики маскирования для необработанных данных является:

 -- Set masking policy --
use role ACCOUNTADMIN;
alter table DB.PUBLIC.RAW_DATA 
    modify column EVERYTHING 
    set masking policy json_address_mask;
  

Политика маскирования применяется к столбцу variant EVERYTHING , структура данных которого выглядит следующим образом:

   {
      "detail": {
        "customAddress": "******",
        "id": 1,
        "latitude": "******",
        "longitude": "******"
      },
      "source": "AAA"
    }
  

Производная таблица является:

 create or replace table DB.SCHEMA_A.TABLE_A
as 
select * from DB.PUBLIC.RAW_DATA 
where everything:source='AAA';

grant select on table DB.schema_A.table_A to role bi_analyst;
  

Представление является:

 create or replace  view DB.SCHEMA_A.VIEW_A  as ( 
select
everything:account::string as account,
everything:detail:latitude::float as detail_latitude,
everything:detail:longitude::float as detail_longitude,
from
DB.PUBLIC.RAW_DATA
where
everything:source::string = 'AAA'

grant select on view DB.SCHEMA_A.VIEW_A to role bi_analyst;
  

В результате RAW_DATA маскируется, TABLE_A вообще не маскируется, VIEW_A возвращает 0 строк при запросе данных с помощью BI_ANALYST роли.

Комментарии:

1. Было бы полезно, если бы вы предоставили доступ к структуре таблицы, определению представления и UDF для маскирования данных

2. Какой UDF вы используете для применения политики маскирования? Если политика маскирования применена к базовой таблице правильно, все представления, которые ссылаются на эту таблицу, также будут маскироваться.

3. @demircioglu здравствуйте, я обновил вопрос кодом и более подробной информацией о данных, надеюсь, это поможет разобраться в моей проблеме

4. @MikeWalton Привет, я только что обновил вопрос, добавив больше деталей. Да, я ожидал, что все представления тоже маскируются, но на самом деле не могу понять, почему это не работает

Ответ №1:

# 1 — Когда вы создаете таблицу из таблицы, содержащей замаскированные данные, вы собираетесь получить данные, к которым роль, создающая новую таблицу, имеет доступ в замаскированной таблице. Итак, в вашем примере TABLE_A имеет демаскированные данные, потому что они были созданы ролью, которая имеет к ним доступ. Политика маскирования автоматически не применяется к новой таблице.

# 2 — Что касается # 2, я полагаю, ваша единственная проблема заключается в том, что JSON в вашем примере неверно сформирован, поэтому вы получаете значения NULL. Когда я исправил этот json на следующий, он отлично работает, используя ту же функцию и политику маскировки, которые вы опубликовали:

 {
"detail":{
"latitude": 132034034.00,
"longitude": 12393438583732,
"id": 1,
"customAddress" : "XXX Road, XXX city, UK"
},
"source": "AAA"
}
  

Результат маскировки:

 {
  "detail": {
    "customAddress": "XXX Road, XXX city, UK",
    "id": 1,
    "latitude": "******",
    "longitude": "******"
  },
  "source": "AAA"
}
  

Комментарии:

1. Извините, json в моем сообщении неверно отформатирован, я исправил это сейчас! Я могу подтвердить, что он правильно отформатирован в snowflak

2. Имеет смысл, что таблица не маскируется вашим объяснением! но для представлений это не так, потому что фактический json правильно отформатирован в фактическом наборе данных

Ответ №2:

Проблема с таблицами, которые не были замаскированы, хорошо объяснена @Mike в его ответе. Решением может быть просто создание производных таблиц с использованием роли, которая ограничена политикой маскирования.

Проблема представлений связана с типом маскируемого значения «******», которое является строковым типом, в то время как фактический тип полей latitude и longitude являются float . При создании представления я по-прежнему приводил поля latitude и longitude к типу float:

 create or replace  view DB.SCHEMA_A.VIEW_A  as ( 
select
everything:account::string as account,
everything:detail:latitude::float as detail_latitude,
everything:detail:longitude::float as detail_longitude,
from
DB.PUBLIC.RAW_DATA
where
everything:source::string = 'AAA'
  

Существует скрытая ошибка при приведении «******» к плавающему значению, но snowflake все равно продолжает создавать представление. Но когда я запрашиваю данные с помощью BI_ANALYST роли, она возвращает строку 0.

Итак, обходным путем является приведение этих полей к вариантному типу:

 create or replace  view DB.SCHEMA_A.VIEW_A  as ( 
select
everything:account::string as account,
everything:detail:latitude::variant as detail_latitude,
everything:detail:longitude::variant as detail_longitude,
from
DB.PUBLIC.RAW_DATA
where
everything:source::string = 'AAA'
  

Что не идеально, поскольку это полностью изменило определение представления, ни одна из ролей не может получить фактический тип данных с плавающей точкой / числом, даже включая accountadmin

Комментарии:

1. Это хорошая уловка в отношении типов данных, являющихся проблемой. Если OP хочет сохранить значение с плавающей точкой в представлении, они также могут просто подключаться 0.0 в качестве значения маски … или NULL и это также сработало бы без необходимости изменять тип данных на variant .