집계 정책으로 엔티티 수준 개인정보 보호 구현

집계 정책으로 엔티티 수준 개인정보 보호 구현

Enterprise Edition 기능

이 기능은 Enterprise Edition(이상)이 필요해요. 업그레이드 문의는 Snowflake Support에 연락해 주세요.

엔티티 수준 개인정보 보호(entity-level privacy)는 집계 정책(aggregation policy)이 제공하는 개인정보 보호를 강화해요. 엔티티 수준 개인정보 보호를 사용하면 Snowflake는 각 그룹이 최소 행 수가 아니라 최소 고유 엔티티 수를 포함하도록 보장할 수 있어요.

출처: Snowflake 문서

본문

엔티티 수준 개인정보 보호를 구현하는지 여부와 관계없이 집계 정책과 관련된 작업과 고려사항의 대부분은 같아요. 집계 정책 작업에 대한 일반적인 내용은 집계 정책(Aggregation policies)을 참고해요.

엔티티 수준 개인정보 보호 정보

*엔티티(entity)*는 논리적 객체(예: 사용자 프로필 또는 가구 정보)에 속하는 속성 집합을 말해요. 이러한 속성은 데이터셋 내에서 엔티티를 식별하는 데 사용될 수 있어요. 엔티티 수준 개인정보 보호는 공유 데이터셋에 저장된 엔티티의 개인정보를 보호하는 개인정보 보호 강화 기술(PET)의 기능이에요. 쿼리가 그 속성이 여러 레코드에 있더라도 엔티티의 민감한 속성을 노출할 수 없도록 보장해요.

엔티티 수준 개인정보 보호를 달성하기 위해 Snowflake는 어떤 열이 엔티티를 식별하는지(엔티티 키, entity key) 지정할 수 있게 해요. 이를 통해 Snowflake는 데이터셋 내에서 특정 엔티티에 속하는 모든 레코드를 식별할 수 있어요. 예를 들어 엔티티 키가 email 열로 정의되면 Snowflake는 [email protected]인 모든 레코드가 같은 엔티티에 속한다고 판단할 수 있어요.

테이블에 여러 엔티티를 정의하면 집계 정책이 각 엔티티 키에 대해 별도로 평가돼요.

정책은 키 열이 쿼리에 나타나지 않아도 쿼리에 적용돼요. 예를 들어 엔티티 키(user_id)에 적용되는 정책이 주어지면 SELECT age FROM T1 GROUP BY age; 쿼리도 각 그룹에서 user_id에 대한 min_group_size 제한을 적용하며, user_id가 쿼리에 나타나지 않는데도 그렇다는 뜻이에요.

엔티티 수준 개인정보 보호 없는 집계 정책

기본적으로 집계 정책은 분석가가 개별 행을 검색하는 대신 데이터를 집계하는 쿼리를 실행하도록 요구해 *행 수준 개인정보 보호(row-level privacy)*를 달성해요. 하지만 행 수준 개인정보 보호는 엔티티의 속성이 여러 행에 있을 때 쿼리가 엔티티의 속성을 노출하는 것을 막지 못해요(예: 트랜잭션 데이터를 포함하는 테이블에서).

예를 들어 스트리밍 서비스 ActonViz가 각 시청자가 프로그램을 볼 때 그 이메일 주소(user_id)와 가구(household_id)를 포함하는 트랜잭션 테이블을 가진다고 가정해 봐요.

user_id household_id program_id watch_time start_time
[email protected] 12345 1 29 2023-09-12 09:00
[email protected] 23485 1 30 2023-09-12 09:00
[email protected] 12345 6 18 2023-09-11 13:00
[email protected] 85456 6 25 2023-09-15 22:00
[email protected] 12345 5 30 2023-09-13 11:00

ActonViz는 집계 정책을 사용해 광고주가 최소 2개 레코드를 포함하는 그룹으로 데이터를 집계하도록 강제할 수 있어요. 이렇게 하면 광고주가 개별 레코드에서 데이터를 검색하는 것을 막을 수 있어요(행 수준 개인정보 보호). 각 시청자와 가구가 테이블에 한 번만 나타나면 그들의 개인정보를 보호하기에 충분해요.

하지만 광고주의 쿼리는 시청자와 그 가구 둘 다에 대한 정보를 여전히 알 수 있어요. 쿼리가 전적으로 가구 12345의 레코드로만 구성된 그룹을 만들 수 있고, 더 심하게는 전적으로 시청자 dave_sr의 레코드로만 구성된 그룹을 만들 수 있어요. 두 경우 모두 그룹의 레코드 수는 ActonViz가 설정한 요구사항(그룹당 최소 2개 레코드)을 충족해요.

엔티티 수준 개인정보 보호가 있는 집계 정책

엔티티 수준 개인정보 보호를 달성하기 위해 Snowflake는 집계 정책을 테이블이나 뷰에 할당할 때 하나 이상의 엔티티 키를 지정할 수 있게 해요. 엔티티 키가 정의된 후 집계 제약(aggregation-constrained) 테이블이나 뷰에 대한 쿼리가 반환하는 그룹은 지정된 수의 행이 아니라 엔티티를 최소한 포함해야 해요.

앞의 예시에서 ActonViz가 각 가구를 고유하게 식별하므로 household_id를 엔티티 키로 정의한다고 가정해 봐요. 각 가구의 개인정보가 이제 강화돼요. 변경 전에는 그룹이 전적으로 household_id = 12345인 레코드로 구성될 수 있었지만, 이제는 서로 다른 household_id 값이 최소 2개 포함되어야 해요.

엔티티 키가 테이블의 기본 키(primary key)와 항상 같지는 않다는 점을 주목해요. 이 예시에서 테이블은 시청자를 고유하게 식별하므로 user_id를 기본 키로 사용할 수 있어요. 하지만 이 경우 ActonViz는 여러 시청자로 구성된 전체 가구의 개인정보를 보호하려 하므로 household_id를 엔티티 키로 선택했어요.

최소 그룹 크기 정보

모든 집계 정책은 최소 그룹 크기를 지정해요. 엔티티 수준 개인정보 보호가 없으면 최소 그룹 크기는 집계 그룹에 포함되어야 하는 레코드 수를 정의해요. 엔티티 키가 지정되면 최소 그룹 크기는 최종 결과에 나타나기 위해 그룹에 나타나야 하는 최소 고유 엔티티 수를 정의해요. SUM, AVG 같은 집계 함수는 그룹 하나를 반환하고, GROUP BY 열은 그룹화된 열의 고유 값마다 그룹 하나를 반환한다는 점을 기억해요.

다음 열 수준 정책은 Snowflake가 집계 그룹에 충분한 엔티티가 있는지 계산하는 방법에 영향을 주지 않아요.

  • 프로젝션 정책(projection policy)은 집계 정책 이후에 적용돼요.
  • 마스킹 정책(masking policy)은 집계 정책 이전에 적용돼요. 모든 집계 함수 또는 정책은 마스킹된 데이터에 대해 작동해요.

이름 참조가 여러 번 사용되는 경우(예: JOIN 또는 UNION 연산자에서) Snowflake는 각 데이터셋의 각 이름 참조에 대해 최소 그룹 크기를 별도로 강제해요. 이는 참조가 같은 데이터셋을 여러 번 가리킬 때도 적용돼요.

집계 정책으로 엔티티 수준 개인정보 보호 적용

집계 정책으로 엔티티 수준 개인정보 보호를 적용하려면 다음을 수행해요.

  • CREATE AGGREGATION POLICY 명령을 실행해 집계 정책을 만들 때 각 집계 그룹에 포함되어야 하는 엔티티 수를 지정해요.
  • 집계 정책을 테이블이나 뷰에 할당할 때 엔티티 키를 정의해요.

최소 엔티티 수 지정

CREATE AGGREGATION POLICY로 집계 정책을 만드는 구문은 엔티티 키를 사용해 엔티티 수준 개인정보 보호를 달성하더라도 변하지 않아요. AGGREGATION_CONSTRAINT 함수의 MIN_GROUP_SIZE 인자를 사용해 최소 그룹 크기를 계속 지정해요. 엔티티 키를 정의하면 최소 그룹 크기가 그룹의 레코드 수 요구사항에서 그룹의 엔티티 수로 바뀌어요.

예를 들어 다음 코드는 최소 그룹 크기가 5인 집계 정책을 만들어요. 정책을 테이블에 할당할 때 엔티티 키를 정의하는 한 각 집계 그룹은 최소 5개 엔티티를 포함해야 해요.

CREATE AGGREGATION POLICY my_agg_policy
  AS () RETURNS AGGREGATION_CONSTRAINT ->
  AGGREGATION_CONSTRAINT(MIN_GROUP_SIZE => 5);

집계 정책 생성에 대한 완전한 세부사항은 여러 상황에서 다른 제한을 적용하는 조건부 집계 정책의 예시를 포함해 집계 정책 만들기를 참고해요.

엔티티 키 정의

집계 정책을 테이블이나 뷰에 할당할 때 테이블에 대한 엔티티 키를 정의해요. 새 테이블이나 뷰를 만들 때 또는 기존 테이블이나 뷰를 업데이트할 때 엔티티 키를 정의할 수 있어요.

기존 테이블과 뷰의 엔티티 키 정의

ALTER TABLE … SET AGGREGATION POLICY 명령 또는 ALTER VIEW … SET AGGREGATION POLICY 명령을 실행해 집계 정책을 할당할 때 ENTITY KEY 절을 사용해 테이블이나 뷰에서 엔티티의 식별 속성을 포함하는 열(즉 엔티티 키)을 지정해요.

예를 들어 viewership_log 테이블에 집계 정책 my_agg_policy를 할당하면서 엔티티 키를 만들려면 다음을 실행해요.

ALTER TABLE viewership_log
  SET AGGREGATION POLICY my_agg_policy
  ENTITY KEY (first_name,last_name);

first_name과 last_name 열이 엔티티 키이므로 집계 정책은 first_name = joe이고 last_name = peterbilt인 모든 행이 같은 엔티티에 속한다고 판단할 수 있어요.

기존 테이블과 뷰에 여러 엔티티 키 정의

기존 테이블에 여러 엔티티 키를 정의하려면 여러 호출에서 새 키를 추가하거나, 단일 호출에서 여러 키를 추가할 수 있어요. 테이블에 키를 정의하는 것은 추가적(additive)이며, 이전에 정의된 키를 덮어쓰거나 삭제하지 않아요.

두 번의 호출로 엔티티 키 두 개 추가. 첫 번째 키는 두 개의 열로 구성돼요.

ALTER TABLE transactions ADD AGGREGATION POLICY ap ENTITY KEY (user_id, user_email);
ALTER TABLE transactions ADD AGGREGATION POLICY ap ENTITY KEY (vendor_id);

한 번의 호출로 엔티티 키 두 개 추가

ALTER TABLE transactions ADD AGGREGATION POLICY ap ENTITY KEY (user_id) ENTITY KEY (vendor_id);
새 테이블과 뷰의 엔티티 키 정의

CREATE TABLE … WITH AGGREGATION POLICY 명령 또는 CREATE VIEW … WITH AGGREGATION POLICY 명령을 실행해 집계 정책을 할당할 때 ENTITY KEY 절을 사용해 테이블이나 뷰에서 엔티티의 식별 속성을 포함하는 열을 지정해요.

예를 들어 집계 정책을 할당하고 엔티티 키를 정의하면서 새 테이블 t1을 만들려면 다음을 실행해요.

CREATE TABLE t1
  WITH AGGREGATION POLICY my_agg_policy
  ENTITY KEY (first_name,last_name);

first_name과 last_name 열이 엔티티 키이므로 집계 정책은 first_name = joe이고 last_name = peterbilt인 모든 행이 같은 엔티티에 속한다고 판단할 수 있어요.

지연 집계 정책(Deferred Aggregation Policies)

쿼리에 서브쿼리가 있으면 Snowflake는 가장 안쪽 쿼리에서 엔티티 집계 정책을 강제하려고 시도해요. 그 쿼리에 GROUP BY 절이 있고 GROUP BY 열이 집계 정책의 엔티티 키와 일치하면 그 집계 정책은 그 서브쿼리에 적용되지 않고 그 서브쿼리의 상위 쿼리에 적용돼요. 이 지연(deferment)은 GROUP BY 열 집합이 정책의 엔티티 키와 일치하지 않는 쿼리에 도달할 때까지, 또는 최상위 쿼리에 도달할 때까지 체인을 따라 계속돼요. 두 경우 모두 집계 정책이 그 쿼리에 적용돼요. 집계 정책은 쿼리 체인에서 한 번만 적용돼요.

예를 들어 엔티티 키가 (name, zipcode)인 집계 정책 my_agg_policy가 있다고 가정해 봐요. 다음 의사 쿼리에서 내부 쿼리는 my_agg_policy의 엔티티 키와 일치하는 GROUP BY 집합을 가지므로 정책이 그 상위 쿼리로 지연돼요. 상위 쿼리에서 GROUP BY 열도 정책 열과 일치하지만, 상위 쿼리는 최상위 쿼리이므로 정책이 그곳에 적용돼요.

SELECT age, name, zipcode FROM(                        -- Outermost query: my_agg_policy enforced.
  SELECT name, zipcode FROM T GROUP BY name, zipcode   -- Matches my_agg_policy entity key: my_agg_policy deferred
)
  GROUP BY age, name, zipcode;

GROUP BY 열이 엔티티 키 열의 상위집합(superset)이면 지연을 트리거할 수 있으며, 정책은 GROUP BY 열이 일치할 때만 지연된다는 점을 주목해요. 집계 함수는 지연을 트리거하지 않아요.

각 집계 정책은 쿼리의 모든 쿼리 블록에 별도로 적용돼요. 집합 연산자(예: UNION)를 통해 여러 블록으로 구성된 쿼리는 각 쿼리 블록에 대해 집계 정책을 별도로 평가해요.

집계 지연은 다음 예시에서 보여주는 것처럼 몇 가지 유용한 효과가 있어요.

지연 예시

엔티티가 (zipcode, email)로 정의된 사용자를 "낮은 지출자(low spenders)"와 "높은 지출자(high spenders)" 두 버킷으로 집계하려 한다고 가정해 봐요. 지연은 다음 예시에서와 같이 이것이 작동하게 해요. 지연이 없으면 내부 쿼리가 NULL을 반환하는데, 각 그룹이 하나의 (zipcode, email) 엔티티로 구성되어 min_group_size가 1보다 큰 값으로 설정되면 억제되기 때문이에요.

WITH bucketed AS (
  SELECT
    CASE
      WHEN SUM(transaction_amount) BETWEEN 0 AND 100 THEN 'low'
      WHEN SUM(transaction_amount) BETWEEN 101 AND 100000 THEN 'high'
    END AS transaction_bucket,
    zipcode,               -- zipcode and email need not appear in the select list, but this lets us compute entity_count below
    email
  FROM my_transactions
  GROUP BY zipcode, email  -- This would not work if it was only GROUP BY zipcode, since the entity key is (zipcode, email)
)
SELECT
  transaction_bucket,
  COUNT(DISTINCT zipcode, email) AS entity_count
FROM
  bucketed
GROUP BY transaction_bucket;

여러 정책 지연

테이블에 여러 집계 정책이 있으면 각 집계 정책이 독립적으로 평가되고 가능하면 지연돼요. 테이블에 여러 집계 정책이 있다면 쿼리를 주의 깊게 설계해야 해요. 서로 다른 정책이 서로 다른 쿼리 수준에 적용되면 예기치 않은 결과가 발생할 수 있기 때문이에요.

예를 들어 두 개의 개별 집계 정책이 있는 테이블에서 사용자를 높은 지출자와 낮은 지출자 범주로 버킷으로 만들려는 중첩 쿼리를 시도할 때 발생할 수 있는 문제가 여기 있어요.

테이블 T:

user_id, vendor_id, zipcode, email,         transaction_amount
   1     1001       90000    [email protected]        100
   1     1001       90000    [email protected]         50
   2     2001       90001    [email protected]         12
   2     2001       90001    [email protected]          5
   3     3001       90002    [email protected]         40

집계 정책:

  • user_policy: min_group_size = 3, 엔티티 키 = (user_id)
  • vendor_policy: min_group_size = 2, 엔티티 키 = (vendor_id)

사용자를 높은/낮은 지출자로 버킷으로 만드는 쿼리:

WITH amounts AS (
  SELECT
    user_id,
    IFF(SUM(transaction_amount) > 50, 'high', 'low') AS bucket
  FROM T
  GROUP BY user_id -- user_policy is deferred, but vendor_policy is enforced
)
SELECT COUNT(*) FROM amounts GROUP BY bucket

예기치 않은 결과:

내부 쿼리에서 vendor_policy가 적용돼요. 각 행은 user_id로 그룹화되는데, user_id 각각에 해당하는 vendor_id는 하나뿐이므로 vendor_policy 최소 그룹 크기를 위반하고, 3명의 서로 다른 고객이 "high" 버킷에 속하더라도 내부 쿼리는 NULL을 반환해요.

엔티티 키 제약 제거

단일 엔티티 키에 대한 집계 정책 제거:

-- Drop agg policy ap associated with entity key user_id
ALTER TABLE transactions DROP AGGREGATION POLICY ap ENTITY KEY (user_id)

여러 엔티티 키에 대한 집계 정책 제거는 각 정책을 별도로 제거해요.

-- Drop the agg policies associated with two separate keys
ALTER TABLE transactions DROP AGGREGATION POLICY ap ENTITY KEY (user_id)
ALTER TABLE transactions DROP AGGREGATION POLICY ap ENTITY KEY (vendor_id)

모든 엔티티와 함께 집계 정책 제거는 DROP 문에서 ENTITY KEY를 생략해요.

-- Drop agg policy ap from the table entirely
ALTER TABLE transactions DROP AGGREGATION POLICY ap

제한사항

여러 엔티티 키나 집계 정책이 정의된 테이블로 작업할 때 다음 제한이 적용돼요.

  • 엔티티 키는 최대 하나의 정책과 연결될 수 있어요. 이미 정책에 매핑된 엔티티 키에 다른 정책을 할당하려고 하면 오류가 발생해요.
  • 정책은 행 수준 개인정보 보호와 엔티티 수준 개인정보 보호 둘 다에 사용될 수 없어요.
  • 행 수준 개인정보 보호에는 정책이 최대 하나만 사용될 수 있어요. 행 수준 집계 정책으로 다른 정책을 할당하려고 하면 오류가 발생해요.

집계 제약 테이블 쿼리

엔티티 키가 있는 집계 제약 테이블을 쿼리하는 요구사항은 엔티티 키가 없는 테이블을 쿼리하는 것과 같아요. 어떤 유형의 쿼리가 이러한 요구사항을 준수하는지에 대한 내용은 쿼리 요구사항을 참고해요.

더 알아보기 (Learn more)