메인 콘텐츠로 건너뛰기
데이터 마스킹은 데이터 보호를 위한 기법으로, 원본 데이터의 형식과 구조는 유지하면서 개인 식별 정보(PII) 또는 민감한 정보를 제거한 버전으로 대체하는 방식입니다. 이 가이드에서는 여러 가지 접근 방식을 사용해 ClickHouse에서 데이터를 마스킹하는 방법을 설명합니다:
  • 마스킹 정책 (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에는 계속 기본 마스킹이 적용됩니다.

해시 기반 마스킹

일관된 마스킹이 필요한 경우(즉, 동일한 입력이 항상 동일한 마스킹 결과를 생성해야 하는 경우)에는 해시 함수를 사용합니다:

마스킹 정책 관리

모든 마스킹 정책 확인:
마스킹 정책 삭제:
기존 정책을 교체하세요:
자세한 내용은 CREATE MASKING POLICY 문서를 참조하십시오.

문자열 대체 함수 사용

기본적인 데이터 마스킹에는 replace 계열 함수로 편리하게 데이터를 마스킹할 수 있습니다: 예를 들어, 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 권한만 부여되도록 역할 기반 접근 제어를 사용해야 합니다. 먼저 역할을 생성합니다:
다음으로, role에 뷰의 SELECT 권한을 부여합니다:
ClickHouse 역할은 누적되므로, 마스킹된 뷰만 볼 수 있어야 하는 사용자에게 어떤 역할을 통해서라도 기본 테이블(base table)에 대한 SELECT 권한이 없도록 해야 합니다. 따라서 안전을 위해 기본 테이블(base table) 접근 권한을 명시적으로 회수해야 합니다:
마지막으로, 적절한 사용자에게 역할을 할당합니다:
이렇게 하면 masked_orders_viewer role이 있는 사용자는 뷰(view)의 마스킹된 데이터만 볼 수 있으며, 테이블(table)의 원래 마스킹되지 않은 데이터는 볼 수 없습니다.

MATERIALIZED 컬럼과 컬럼 수준 접근 제한 사용

별도의 뷰를 만들지 않고 원본 데이터와 함께 마스킹된 버전의 데이터를 저장할 수도 있습니다. 이를 위해 materialized 컬럼을 사용할 수 있습니다. 이러한 컬럼의 값은 행이 삽입될 때 지정된 materialized 표현식에 따라 자동으로 계산되며, 이를 사용해 데이터의 마스킹된 버전을 담은 새 컬럼을 만들 수 있습니다. 앞선 예시와 같이, 마스킹된 데이터를 위한 별도의 VIEW를 만드는 대신 이제 MATERIALIZED를 사용해 마스킹된 컬럼을 생성하겠습니다:
이제 다음 SELECT 쿼리를 실행하면 마스킹된 데이터가 삽입 시점에 ‘구체화되어’ 원래의 마스킹되지 않은 데이터와 함께 저장되는 것을 확인할 수 있습니다. ClickHouse는 기본적으로 SELECT * 쿼리에 materialized 컬럼을 자동으로 포함하지 않으므로, 마스킹된 컬럼은 명시적으로 선택해야 합니다.
Query
Response
사용자가 마스킹된 데이터가 포함된 컬럼에만 접근할 수 있도록 하려면, 역할 기반 접근 제어을 다시 사용해 특정 역할에 orders의 마스킹된 컬럼에 대해서만 SELECT 권한이 부여되도록 설정할 수 있습니다. 이전에 만든 역할을 다시 생성합니다:
다음으로, orders 테이블에 대한 SELECT 권한을 부여합니다:
민감한 컬럼에 대한 접근 권한을 회수하세요:
마지막으로, 해당 역할을 적절한 사용자에게 할당합니다:
orders 테이블에 마스킹된 데이터만 저장하려는 경우, 마스킹되지 않은 민감한 컬럼을 EPHEMERAL로 지정할 수 있으며, 이렇게 하면 이 유형의 컬럼은 테이블에 저장되지 않습니다.
이제 앞서와 동일한 쿼리를 실행하면 마스킹된 데이터만 구체화되어 테이블에 삽입된 것을 확인할 수 있습니다:
Query
Response

로그 데이터에 쿼리 마스킹 규칙 사용

특히 로그 데이터만 마스킹하려는 ClickHouse OSS 사용자는 데이터를 마스킹하기 위해 query masking rules(로그 마스킹)를 사용할 수 있습니다. 이를 위해 서버 구성에서 정규식 기반 마스킹 규칙을 정의할 수 있습니다. 이 규칙은 쿼리와 모든 로그 메시지가 서버 로그 또는 시스템 테이블(예: system.query_log, system.text_log, system.processes)에 저장되기 전에 적용됩니다. 이렇게 하면 민감한 데이터가 로그에만 유출되는 것을 방지할 수 있습니다. 쿼리 결과의 데이터는 마스킹되지 않는다는 점에 유의하십시오. 예를 들어 주민등록번호를 마스킹하려면 다음 규칙을 서버 구성에 추가할 수 있습니다:
마지막 수정일 2026년 6월 12일