정책으로 보호된 데이터 공유하기

정책으로 보호된 데이터 공유하기

데이터 공유 소비자는 공유된 데이터베이스 역할(database role)을 사용해 마스킹 정책(masking policy)이나 행 접근 정책(row access policy)으로 보호된 공유 데이터에 접근할 수 있어요.

출처: Snowflake User Guide - Share policy-protected data

본문

개요

데이터 공유 프로바이더는 데이터베이스 역할을 공유해 데이터 공유 소비자가 정책으로 보호된 데이터에 접근할 수 있게 해줘요. 프로바이더는 IS_DATABASE_ROLE_IN_SESSION 함수를 호출하는 정책을 정의해 공유된 데이터베이스 역할이나 데이터베이스 역할을 담은 매핑 테이블 컬럼을 평가해요. 이렇게 하면 프로바이더가 데이터를 공유하는 옵션이 더 많아지고, 소비자가 프로바이더가 제공하는 민감한 데이터에 접근할 수 있게 돼요.

정책과 보호된 테이블이 서로 다른 데이터베이스에 있을 때 프로바이더는 다음을 수행해야 해요.

  • 보호된 테이블과 같은 데이터베이스에 데이터베이스 역할을 만들어요.
  • 보호된 테이블을 포함하는 셰어에 데이터베이스 역할을 부여해요.
  • 보호된 테이블을 포함하는 데이터베이스를 소비자 계정과 공유해요.

소비자가 셰어에서 데이터베이스를 만들면 셰어 안의 데이터베이스 역할이 셰어에서 데이터베이스를 만드는 역할에 부여돼요. 이렇게 하면 소비자 계정의 계정 역할이 그 데이터베이스 역할을 지정하는 정책 조건을 충족해 공유 데이터에 접근할 수 있어요.

정책으로 보호된 공유 데이터에 접근하려면 소비자는 공유 데이터베이스 역할이 들어 있는 데이터베이스를 지정해 그 데이터베이스 역할을 현재 세션에서 활성화해야 해요. 여기서 데이터베이스 역할을 활성화한다는 것은 그 역할이 사용자의 현재 역할의 역할 계층에 포함된다는 뜻이에요. 이 공유 데이터베이스를 지정하지 않으면 소비자 계정의 사용자는 정책으로 보호된 공유 데이터에 접근할 수 없어요. 데이터베이스를 지정하는 방법은 두 가지예요.

  • USE <object> 명령으로 세션에서 데이터베이스를 활성화하거나 worksheet에서 데이터베이스를 선택해요. 예:
    USE DATABASE mounted_db;
    
    여기서 mounted_db는 소비자가 셰어에서 만든 데이터베이스 이름이에요.
  • 특정 쿼리에 대해 데이터베이스 역할과 같은 데이터베이스 안에 있는 객체의 정규화된 이름을 사용해요. 예:
    SELECT * FROM mounted_db.myschema.mytable;
    

함수 호출하기

IS_DATABASE_ROLE_IN_SESSION 함수에는 문자열 리터럴 또는 비리터럴(즉 컬럼 이름) 두 가지 방식으로 인자를 지정할 수 있어요.

  • IS_DATABASE_ROLE_IN_SESSION 함수에 데이터베이스 역할을 문자열로 지정하면 함수 호출 결과는 호출 방식에 따라 달라져요. 예:
    • worksheet에서는 Snowflake가 세션에서 사용 중인 데이터베이스 또는 쿼리에 지정된 데이터베이스를 봐요. 이는 프로바이더 계정과 소비자 계정 모두에 적용돼요.
    • 정책, UDF, 또는 뷰에서는 Snowflake가 보호된 객체가 들어 있는 데이터베이스를 봐요. 이 객체들이 공유되지 않고 데이터베이스 역할이 다른 데이터베이스에 정의되어 있으면 함수는 False로 평가돼요.
  • IS_DATABASE_ROLE_IN_SESSION 함수에 컬럼 이름을 인자로 지정하면:
    • 테이블 쿼리가 함수를 호출하면 컬럼은 그 컬럼을 포함한 테이블의 테이블 식별자에 매핑돼요. Snowflake는 그 뒤 테이블을 포함한 데이터베이스의 데이터베이스 역할을 봐요. 예를 들어 AUTHZ_ROLE(허가된 역할) 컬럼을 인자로 지정하려면:
      SELECT * FROM mydb.myschema.t WHERE IS_DATABASE_ROLE_IN_SESSION(AUTHZ_ROLE);
      
    • 마스킹 정책, 행 접근 정책, 또는 UDF가 함수를 호출하면 조회는 보호된 테이블이 들어 있는 데이터베이스에서 발생해요.

일반 워크플로

정책에서 IS_DATABASE_ROLE_IN_SESSION 함수로 정책 보호 데이터를 공유하려면, 함수를 호출하는 정책을 만들고 데이터를 공유하는 것과 같은 단계가 필요해요. 요약하면:

  1. 프로바이더가 계정 역할을 만들어요.
  2. 프로바이더가 정책을 만들고 테이블이나 컬럼에 정책을 설정해요.
  3. 프로바이더가 계정 역할로 정책을 테스트해요.
  4. 프로바이더가 데이터베이스 역할을 만들고 그 역할로 정책을 테스트해요.
  5. 프로바이더가 셰어를 만들고 셰어에 권한을 부여하며, 데이터베이스 역할을 셰어에 부여하는 것도 포함해요.
  6. 소비자가 셰어에서 데이터베이스(마운트된 데이터베이스)를 만들어요.
  7. 소비자가 정책으로 보호된 공유 객체를 쿼리해요.

예시: 모든 객체가 같은 데이터베이스에 있는 경우

이 예시에서 데이터베이스 역할, 마스킹 정책, 보호된 테이블이 모두 mydb라는 같은 데이터베이스에 있어요.

  • 데이터베이스 역할은 analyst_dbrole과 support_dbrole이에요.
  • 마스킹 정책은 다음과 같이 정의돼요.
    CREATE OR REPLACE MASKING POLICY mydb.policies.email_mask
      AS (val string) RETURNS string ->
        CASE
          WHEN IS_DATABASE_ROLE_IN_SESSION('ANALYST_DBROLE')
            THEN val
          WHEN IS_DATABASE_ROLE_IN_SESSION('SUPPORT_DBROLE')
            THEN REGEXP_REPLACE(val, '.+\@', '*****@')
          ELSE '********'
        END
      COMMENT = 'use database role for shared data'
      ;
    
  • EMAIL 컬럼은 mydb.tables.empl_info라는 테이블에 있고, 이 컬럼에 마스킹 정책이 설정돼 있어요.

다음 단계로 데이터베이스 mydb를 공유하고 소비자가 공유 데이터베이스 역할을 사용해 공유 마스킹 정책으로 보호된 공유 데이터를 쿼리하게 해요. 이 단계들은 프로바이더가 이미 계정 역할과 데이터베이스 역할로 EMAIL 컬럼의 마스킹 정책을 테스트했다고 가정해요.

  1. 프로바이더 계정에서 CREATE SHARE 명령으로 analyst 데이터베이스 역할을 위한 셰어를 만들어요.
    USE ROLE r1;
    CREATE SHARE analyst_share;
    
  2. 셰어에 권한을 부여해요. 각 셰어에 동일한 권한이 필요해요.
    USE ROLE r1;
    GRANT USAGE ON DATABASE mydb TO SHARE analyst_share;
    GRANT USAGE ON SCHEMA mydb.tables TO SHARE analyst_share;
    GRANT SELECT ON TABLE mydb.tables.empl_info TO SHARE analyst_share;
    GRANT DATABASE ROLE analyst_dbrole TO SHARE analyst_share;
    
  3. 소비자 계정을 셰어에 추가해요.
    ALTER SHARE analyst_share ADD ACCOUNTS = consumer_account;
    
  4. 소비자 계정에서 계정 역할 r1을 만들고 이 역할에 셰어를 가져올 권한을 부여해요.
    USE ROLE ACCOUNTADMIN;
    CREATE ROLE r1;
    GRANT USAGE ON WAREHOUSE my_warehouse TO ROLE r1;
    GRANT CREATE DATABASE ON ACCOUNT TO ROLE r1;
    GRANT IMPORT SHARE ON ACCOUNT TO ROLE r1;
    GRANT ROLE r1 TO ROLE ACCOUNTADMIN;
    
  5. 셰어를 가져와요.
    USE ROLE r1;
    CREATE DATABASE mounted_db FROM SHARE provider_account.analyst_share;
    
  6. 데이터베이스 역할이 세션에 있는지 확인해요.
    USE DATABASE mounted_db;
    USE SCHEMA mounted_db.tables;
    SELECT IS_DATABASE_ROLE_IN_SESSION('ANALYST_DBROLE');
    
    SELECT 문은 True를 반환해야 해요.
  7. 보호된 테이블을 쿼리해요.
    SELECT * FROM empl_info;
    
    SELECT 문은 마스킹되지 않은 이메일 주소를 반환해야 해요.
  8. 데이터베이스 역할을 계정 역할에 부여해 그 역할을 가진 사용자가 마스킹 정책 정의에 따라 보호된 테이블을 쿼리하고 데이터를 볼 수 있게 해요. 이전 두 단계를 반복한 뒤, support_dbrole 데이터베이스 역할이 부여된 사용자는 부분적으로 마스킹된 이메일 주소를 봐야 해요.

예시: 마스킹 정책과 보호된 데이터가 서로 다른 데이터베이스에 있는 경우

정책과 보호된 테이블이 서로 다른 데이터베이스에 있을 때는 보호된 테이블이 들어 있는 데이터베이스를 소비자와 공유해요. 예를 들어:

  • mydb1에 마스킹 정책이 있어요.
  • mydb2에 EMAIL 컬럼을 포함하는 mydb2.tables.empl_info 테이블이 있어요. 마스킹 정책은 이 컬럼에 설정돼 있어요. 테이블과 데이터베이스 역할 analyst_dbrole을 같은 데이터베이스에 그룹화해야 해요.

프로바이더는 이전 예시와 동일한 절차로 셰어를 만들고, 셰어에 권한을 부여하고, 데이터베이스 역할을 셰어에 부여해요. 소비자도 이전 예시와 동일한 절차로 셰어에서 데이터베이스를 만들어요. 다만 소비자는 데이터베이스 역할을 활성화하기 위해 보호된 테이블이 들어 있는 데이터베이스를 사용 중이어야 해요. 그런 다음 소비자는 테이블의 정규화된 이름을 지정해 보호된 테이블을 쿼리할 수 있어요.

  1. 프로바이더 계정에서 각 데이터베이스에 대한 셰어를 만들기 위해 CREATE SHARE 명령을 실행해요.
    USE ROLE r1;
    CREATE SHARE analyst_policy_share;
    CREATE SHARE analyst_table_share;
    
  2. analyst_table_share라는 셰어에 권한을 부여해요.
    USE ROLE r1;
    GRANT USAGE ON SCHEMA mydb2.tables TO SHARE analyst_table_share;
    GRANT SELECT ON TABLE mydb2.tables.empl_info TO SHARE analyst_table_share;
    GRANT DATABASE ROLE mydb2.analyst_dbrole TO SHARE analyst_table_share;
    
  3. 소비자 계정을 셰어에 추가해요.
    ALTER SHARE analyst_table_share ADD ACCOUNTS = consumer_account;
    
  4. 소비자 계정에서 계정 역할 r1을 만들고 이 역할에 셰어를 가져올 권한을 부여해요.
    USE ROLE ACCOUNTADMIN;
    CREATE ROLE r1;
    GRANT USAGE ON WAREHOUSE my_warehouse TO ROLE r1;
    GRANT CREATE DATABASE ON ACCOUNT TO ROLE r1;
    GRANT IMPORT SHARE ON ACCOUNT TO ROLE r1;
    GRANT ROLE r1 TO ROLE ACCOUNTADMIN;
    
  5. 보호된 테이블과 데이터베이스 역할을 포함하는 셰어를 가져와요.
    USE ROLE r1;
    CREATE DATABASE mounted_db2 FROM SHARE provider_account.analyst_table_share;
    
  6. 데이터베이스 역할이 세션에 있는지 확인해요.
    USE DATABASE mounted_db2;
    USE SCHEMA mounted_db2.tables;
    SELECT IS_DATABASE_ROLE_IN_SESSION('ANALYST_DBROLE');
    
    SELECT 문은 True를 반환해야 해요.
  7. 보호된 테이블을 쿼리해요.
    SELECT * FROM mounted_db2.tables.empl_info;
    
    SELECT 문은 마스킹되지 않은 이메일 주소를 반환해야 해요.

예시: 매핑 테이블이 없는 행 접근 정책

이 예시에서 행 접근 정책은 IS_DATABASE_ROLE_IN_SESSION 함수를 호출해 authz_role(허가된 역할) 컬럼에서 역할 이름을 조회해요. 비리터럴 문법이며 함수 조회는 보호된 테이블이 들어 있는 데이터베이스에서 발생해요.

정책을 만들어요:

CREATE OR REPLACE ROW ACCESS POLICY rap_authz_role AS
  (authz_role string)
  RETURNS boolean ->
    IS_DATABASE_ROLE_IN_SESSION (authz_role);

테이블에 정책을 추가해요:

ALTER TABLE allowed_roles
  ADD ROW ACCESS POLICY rap_authz_role ON (authz_role);

프로바이더는 마스킹 정책 예시에서 본 것처럼 단일 데이터베이스 또는 여러 데이터베이스의 객체를 공유할 수 있어요. 소비자는 프로바이더가 제공하는 각 데이터베이스에 대해 셰어에서 데이터베이스를 만드는 동일한 절차를 따라요.

예시: 매핑 테이블이 있는 행 접근 정책

이 예시에서 행 접근 정책은 IS_DATABASE_ROLE_IN_SESSION 함수를 호출해 role_name이라는 매핑 테이블 컬럼에서 허가된 역할을 조회해요. 비리터럴 문법이며 함수 조회는 보호된 테이블이 들어 있는 데이터베이스에서 발생해요. 이 시나리오에서는 매핑 테이블이 보호된 테이블과 같은 데이터베이스에 있어야 해요. 정책을 만든 뒤 authz_role 컬럼을 포함한 테이블에 정책을 추가해요.

정책을 만들어요:

CREATE OR REPLACE ROW ACCESS POLICY rap_authz_role_map AS
  (authz_role string)
  RETURNS boolean ->
    EXISTS (
      SELECT 1 FROM mapping_table m
        WHERE authz_role = m.key
          AND IS_DATABASE_ROLE_IN_SESSION (m.role_name)
    );

테이블에 정책을 추가해요:

ALTER TABLE allowed_roles
  ADD ROW ACCESS POLICY rap_authz_role_map ON (authz_role);

프로바이더는 단일 또는 여러 데이터베이스의 객체를 공유할 수 있고, 소비자는 각 데이터베이스에 대해 동일한 절차를 따라요.

더 알아보기