CREATE ROW POLICY
CREATE ROW POLICY
사용자가 테이블에서 읽을 수 있는 행을 결정하는 데 사용되는 필터인 행 정책(row policy)을 만들어요.
행 정책은 읽기 전용(readonly) 접근 권한이 있는 사용자에게만 의미가 있어요. 사용자가 테이블을 수정하거나 테이블 간에 파티션을 복사할 수 있으면 행 정책의 제한이 무력화됩니다.
출처: 문서
본문
Syntax:
-- Multiple names on one table target
CREATE [ROW] POLICY [IF NOT EXISTS | OR REPLACE] policy_name [, ...]
[ON CLUSTER cluster_name]
ON { [db.]table | db.* }
[IN access_storage_type]
[[FOR SELECT] USING {condition | NONE}]
[AS {PERMISSIVE | RESTRICTIVE}]
[TO {role1 [, role2 ...] | ALL | ALL EXCEPT role1 [, role2 ...]}]
-- One name on multiple table targets
CREATE [ROW] POLICY [IF NOT EXISTS | OR REPLACE] policy_name
[ON CLUSTER cluster_name]
ON { [db.]table | db.* } [, ...]
[IN access_storage_type]
[[FOR SELECT] USING {condition | NONE}]
[AS {PERMISSIVE | RESTRICTIVE}]
[TO {role1 [, role2 ...] | ALL | ALL EXCEPT role1 [, role2 ...]}]
-- Mixed packing: each name paired with its own table target
CREATE [ROW] POLICY [IF NOT EXISTS | OR REPLACE]
policy_name ON { [db.]table | db.* } [, policy_name ON { [db.]table | db.* } ...]
[ON CLUSTER cluster_name]
[IN access_storage_type]
[[FOR SELECT] USING {condition | NONE}]
[AS {PERMISSIVE | RESTRICTIVE}]
[TO {role1 [, role2 ...] | ALL | ALL EXCEPT role1 [, role2 ...]}]
ParserRowPolicyNames는 세 가지 묶음(packing) 형태를 허용합니다(완전한 데카르트 곱이 아님).
- 여러 이름, 한 대상 —
pol1, pol2 ON table1은 나열된 각 이름을 그 단일 테이블(또는db.*)에 만들어요. - 한 이름, 여러 대상 —
pol1 ON table1, table2는 나열된 각 대상에 같은 짧은 이름을 만들어요. - 혼합 쌍 —
p1 ON t1, p2 ON t2는 각 이름을 짝지어진 대상에만 만들어요.
다중 이름 목록은 한 그룹의 다중 테이블 ON 목록과 결합할 수 없어요. p1, p2 ON t1, t2는 거부됩니다. 다중 이름 그룹 뒤에는 같은 문에서 또 다른 쉼표로 구분된 name ON target 그룹을 추가할 수도 없습니다.
선택적 ON CLUSTER는 전체 문에 적용됩니다(하나의 클러스터 이름). ClickHouse는 단일 create에 묶인 정책 이름마다 서로 다른 ON CLUSTER를 받지 않아요. 정책을 다른 클러스터에서 만들어야 하면 별도의 CREATE ROW POLICY 문을 실행하세요.
CREATE ROW POLICY는 정책이 만들어지는 테이블에 대한 CREATE ROW POLICY 권한이 필요해요. OR REPLACE는 적용 대상 역할을 포함해 같은 이름의 기존 정책을 버리므로, 그 테이블에 대한 DROP ROW POLICY 권한이 추가로 필요합니다. DROP ROW POLICY 권한은 정책이 이미 존재하는지와 상관없이 필요하므로, 이 문으로 어떤 정책이 존재하는지 알아낼 수 없어요.
Multiple names and tables
유효:
-- Several policy names, one table
CREATE ROW POLICY pol1, pol2, pol3 ON table1
FOR SELECT USING id = 1
TO accountant;
-- One policy name, several tables
CREATE ROW POLICY IF NOT EXISTS pol1 ON table1, table2, table3
FOR SELECT USING id = 1
TO accountant;
-- Mixed packing: different name per table
CREATE ROW POLICY p4 ON db.table, p5 ON db2.table2
USING a = b;
-- Same policy on several tables, on a cluster
CREATE ROW POLICY IF NOT EXISTS pol1 ON CLUSTER replicated_cluster ON table1, table2
FOR SELECT USING id = 1
TO accountant;
무효:
-- Multi-name × multi-table in one ON-group (not a Cartesian product)
CREATE ROW POLICY p1, p2 ON t1, t2
FOR SELECT USING id = 1
TO accountant;
-- Different clusters per name in one statement
CREATE ROW POLICY pol1 ON CLUSTER cluster1 ON table1, pol2 ON CLUSTER cluster2 ON table2
USING Clause
행을 필터링하는 조건을 지정할 수 있게 해줘요. 행에 대해 조건이 0이 아닌 값으로 계산되면 사용자는 그 행을 볼 수 있어요.
TO Clause
TO 섹션에서 이 정책이 동작해야 하는 사용자와 역할의 목록을 제공할 수 있어요. 예: CREATE ROW POLICY ... TO accountant, john@localhost.
키워드 ALL은 현재 사용자를 포함한 모든 ClickHouse 사용자를 의미해요. 키워드 ALL EXCEPT는 전체 사용자 목록에서 일부 사용자를 제외할 수 있게 합니다. 예: CREATE ROW POLICY ... TO ALL EXCEPT accountant, john@localhost.
TO 섹션에 나열된 역할(ALL EXCEPT 뒤의 것 포함)은 사용자에게 부여된 모든 역할이 아니라 현재 사용자의 활성 역할(system.enabled_roles)과 비교됩니다. 따라서 SET ROLE이 어떤 정책이 적용되는지 바꿀 수 있어요.
AS Clause
같은 테이블에서 같은 사용자에 대해 한 번에 하나 이상의 정책을 활성화하는 것이 허용돼요. 그래서 여러 정책의 조건을 결합하는 방법이 필요합니다.
기본적으로 정책은 불리언 OR 연산자로 결합됩니다. 예를 들어 다음 정책들은:
CREATE ROW POLICY pol1 ON mydb.table1 USING b=1 TO mira, peter
CREATE ROW POLICY pol2 ON mydb.table1 USING c=2 TO peter, antonio
사용자 peter가 b=1 또는 c=2인 행을 볼 수 있게 합니다.
AS 절은 정책이 다른 정책과 어떻게 결합되어야 하는지를 지정해요. 정책은 permissive 또는 restrictive일 수 있어요. 기본적으로 정책은 permissive이며, 불리언 OR 연산자로 결합됩니다.
정책은 대안으로 restrictive로 정의할 수 있어요. Restrictive 정책은 불리언 AND 연산자로 결합됩니다.
일반 공식은 이래요.
row_is_visible = (one or more of the conditions from the permissive policies that apply to the current user and their enabled roles are non-zero) AND
(all of the conditions from the restrictive policies that apply to the current user and their enabled roles are non-zero)
적용되는 permissive 조건이 없으면, access_control_improvements.users_without_row_policies_can_read_rows가 기본적으로 활성화되어 있으므로 첫 조건은 효과가 없고 restrictive 정책만 결정합니다. 따라서 적용되는 조건이 없는 사용자는 모든 행을 보게 되고, 기본적으로 비활성화된 access_control_improvements.throw_on_unmatched_row_policies는 테이블에 조건이 있지만 그중 어떤 것도 적용되지 않을 때 대신 예외를 발생시킵니다.
예를 들어 다음 정책들은:
CREATE ROW POLICY pol1 ON mydb.table1 USING b=1 TO mira, peter
CREATE ROW POLICY pol2 ON mydb.table1 USING c=2 AS RESTRICTIVE TO peter, antonio
사용자 peter가 b=1 AND c=2 둘 다일 때만 행을 볼 수 있게 합니다.
데이터베이스 정책은 테이블 정책과 결합됩니다.
예를 들어 다음 정책들은:
CREATE ROW POLICY pol1 ON mydb.* USING b=1 TO mira, peter
CREATE ROW POLICY pol2 ON mydb.table1 USING c=2 AS RESTRICTIVE TO peter, antonio
사용자 peter가 b=1 AND c=2 둘 다일 때만 table1 행을 볼 수 있게 하지만, mydb의 다른 테이블은 사용자에게 b=1 정책만 적용됩니다.
Distributed and remote-backed tables
행 정책은 테이블 데이터가 실제로 읽히는 곳에서 행을 필터링해요. Distributed 테이블처럼 읽기를 원격 서버에 위임하는 테이블(또는 그 위의 래퍼, 예: Distributed 대상을 가진 materialized view)은 쿼리 텍스트만 원격 서버로 보내므로 원격 읽기에 정책 필터를 적용할 수 없어요. 필터가 조용히 빠지는 것을 방지하기 위해, 정책이 적용되는 사용자가 그런 테이블에 대해 보내는 쿼리는 ILLEGAL_PREWHERE 오류로 거부됩니다.
대신 각 원격 서버의 기본 로컬 테이블에 정책을 정의하세요. 보내진 쿼리가 그 테이블을 읽을 때 정책이 그곳에 적용됩니다.
-- Filters reads of local_table on this server, including reads shipped by a Distributed table over it.
CREATE ROW POLICY filter ON mydb.local_table USING a < 1000 TO john;
이것은 쿼리가 텍스트로 보내지는 동안(기본값) 동작해요. serialize_query_plan = 1이면 initiator가 이미 구성된 읽기 계획을 전송하고, 그러한 계획을 실행하는 원격 서버는 자체 행 정책을 적용하지 않으므로 local_table 위의 Distributed 테이블 읽기가 필터링되지 않은 행을 반환합니다. 행 정책이 적용되어야 하는 사용자는 serialize_query_plan = 0을 유지하세요. issue #112891을 참고하세요.
ON CLUSTER Clause
클러스터에서 행 정책을 만들 수 있게 해주며, Distributed DDL을 참고하세요. 이것은 또한 클러스터의 모든 서버의 로컬 테이블에 정책을 만드는 편리한 방법이에요.
Examples
CREATE ROW POLICY filter1 ON mydb.mytable USING a<1000 TO accountant, john@localhost
CREATE ROW POLICY filter2 ON mydb.mytable USING a<1000 AND b=5 TO ALL EXCEPT mira
CREATE ROW POLICY filter3 ON mydb.mytable USING 1 TO admin
CREATE ROW POLICY filter4 ON mydb.* USING 1 TO admin