- 마스킹 정책 (ClickHouse Cloud, 25.12+): 특정 사용자/역할에 대해 쿼리 시점에 적용되는 네이티브 동적 마스킹
- 문자열 대체 함수: 내장 함수를 사용한 기본적인 마스킹
- 마스킹된 뷰: 변환 로직이 포함된 뷰 생성
- materialized 컬럼: 원본 데이터와 함께 마스킹된 버전 저장
- 쿼리 마스킹 규칙: 로그의 민감한 데이터 마스킹 (ClickHouse OSS)
마스킹 정책 사용 (ClickHouse Cloud)
마스킹 정책은 ClickHouse Cloud 버전 25.12부터 사용할 수 있습니다.
CREATE MASKING POLICY SQL 문은 특정 사용자 또는 역할에 대해 쿼리 시점에 컬럼 값을 동적으로 마스킹하는 네이티브 방식을 제공합니다. 다른 방식과 달리 마스킹 정책은 별도의 뷰를 생성하거나 마스킹된 데이터를 저장할 필요가 없습니다. 사용자가 테이블에 쿼리할 때 변환이 투명하게 적용됩니다.
기본 마스킹 정책
orders 테이블을 생성해 보겠습니다:
masked_data_viewer 역할에 적용할 마스킹 정책을 생성하세요:
masked_data_viewer 역할이 부여된 사용자가 orders 테이블을 쿼리하면 마스킹된 데이터가 자동으로 표시됩니다:
Query
Response (for masked_data_viewer role)
masked_data_viewer 역할이 없는 사용자는 마스킹되지 않은 원본 데이터를 볼 수 있습니다.
조건부 마스킹
WHERE 절을 사용하면 특정 행에만 마스킹을 적용할 수 있습니다. 예를 들어, 고액 주문에만 마스킹을 적용하는 경우는 다음과 같습니다:
우선순위가 있는 여러 마스킹 정책
PRIORITY 절을 사용하여 어떤 변환을 적용할지 제어합니다. 우선순위 값이 높을수록 나중에 적용됩니다:
total_amount > 100인 주문은 name 컬럼에 대해 refined_masking 정책(우선순위 10)이 basic_masking 정책(우선순위 0)을 재정의하고, email에는 계속 기본 마스킹이 적용됩니다.
해시 기반 마스킹
마스킹 정책 관리
문자열 대체 함수 사용
replace 계열 함수로 편리하게 데이터를 마스킹할 수 있습니다:
| Function | Description |
|---|---|
replaceOne | 검색 대상 문자열(haystack)에서 pattern이 처음 나타나는 부분을 지정된 대체 문자열로 바꿉니다. |
replaceAll | 검색 대상 문자열(haystack)에서 pattern이 나타나는 모든 부분을 지정된 대체 문자열로 바꿉니다. |
replaceRegexpOne | 검색 대상 문자열(haystack)에서 정규식 pattern(re2 구문)과 일치하는 부분 문자열의 첫 번째 항목을 지정된 대체 문자열로 바꿉니다. |
replaceRegexpAll | 검색 대상 문자열(haystack)에서 정규식 pattern(re2 구문)과 일치하는 부분 문자열의 모든 항목을 지정된 대체 문자열로 바꿉니다. |
replaceOne 함수를 사용하면 이름 “John Smith”를 자리 표시자 [CUSTOMER_NAME]로 바꿀 수 있습니다:
Query
Response
replaceRegexpOne을 사용해 모든 고객 이름을 바꿀 수 있습니다:
Query
Response
replaceRegexpAll 함수를 사용해 사회보장번호는 마지막 4자리만 남기고 마스킹할 수 있습니다.
Query
\3은 세 번째 캡처 그룹을 결과 문자열에 치환하는 데 사용되며, 결과는 다음과 같습니다:
Response
마스킹된 VIEW 생성
VIEW는 앞서 언급한 문자열 함수와 함께 사용하여 민감한 데이터가 포함된 컬럼에, 사용자에게 표시되기 전에 변환을 적용할 수 있습니다.
이렇게 하면 원본 데이터는 변경되지 않고, 뷰를 쿼리하는 사용자는 마스킹된 데이터만 보게 됩니다.
예시를 위해 고객 주문 기록을 저장하는 테이블이 있다고 가정해 보겠습니다.
특정 직원 그룹이 이 정보를 볼 수 있도록 하되, 고객의 전체 정보는 볼 수 없게 하려고 합니다.
아래 쿼리를 실행하여 예시 테이블 orders를 생성하고, 여기에 가상의 고객 주문 기록 몇 개를 삽입하십시오:
masked_orders 뷰를 생성하세요:
SELECT 절에서는 부분적으로 마스킹하려는 민감한 정보가 포함된 name, email, phone, shipping_address 필드에 대해 replaceRegexpOne을 사용해 변환을 정의합니다.
뷰에서 데이터를 조회합니다:
Query
Response
SELECT 권한을 부여합니다:
SELECT 권한이 없도록 해야 합니다.
따라서 안전을 위해 기본 테이블(base table) 접근 권한을 명시적으로 회수해야 합니다:
masked_orders_viewer role이 있는 사용자는
뷰(view)의 마스킹된 데이터만 볼 수 있으며, 테이블(table)의 원래 마스킹되지 않은 데이터는 볼 수 없습니다.
MATERIALIZED 컬럼과 컬럼 수준 접근 제한 사용
VIEW를 만드는 대신 이제 MATERIALIZED를 사용해 마스킹된 컬럼을 생성하겠습니다:
SELECT * 쿼리에 materialized 컬럼을 자동으로 포함하지 않으므로, 마스킹된 컬럼은 명시적으로 선택해야 합니다.
Query
Response
orders의 마스킹된 컬럼에 대해서만 SELECT 권한이 부여되도록 설정할 수 있습니다.
이전에 만든 역할을 다시 생성합니다:
orders 테이블에 대한 SELECT 권한을 부여합니다:
orders 테이블에 마스킹된 데이터만 저장하려는 경우,
마스킹되지 않은 민감한 컬럼을 EPHEMERAL로 지정할 수 있으며,
이렇게 하면 이 유형의 컬럼은 테이블에 저장되지 않습니다.
Query
Response
로그 데이터에 쿼리 마스킹 규칙 사용
system.query_log, system.text_log, system.processes)에 저장되기 전에 적용됩니다.
이렇게 하면 민감한 데이터가 로그에만 유출되는 것을 방지할 수 있습니다.
쿼리 결과의 데이터는 마스킹되지 않는다는 점에 유의하십시오.
예를 들어 주민등록번호를 마스킹하려면 다음 규칙을 서버 구성에 추가할 수 있습니다: