ParserRowPolicyNames поддерживает три формы группировки (не полный декартов продукт):
- Несколько имён, одна цель —
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 не поддерживает отдельное ON CLUSTER для каждого имени политики, сгруппированного в одном операторе создания — если политики необходимо создать в разных кластерах, выполните отдельные операторы CREATE ROW POLICY.
Для CREATE ROW POLICY требуется привилегия CREATE ROW POLICY на таблицу, для которой создаётся политика. OR REPLACE отбрасывает существующую политику с тем же именем, включая роли, к которым она применяется, поэтому дополнительно требуется привилегия DROP ROW POLICY на эту таблицу. Привилегия DROP ROW POLICY требуется независимо от того, существует политика или нет, поэтому этот оператор нельзя использовать для того, чтобы узнать, какие политики существуют.
Несколько имён и таблиц
Допустимо:Предложение USING
Задаёт условие фильтрации для таблицы. Пользователь видит только те строки, для которых условие истинно (то есть интерпретируется как ненулевое значение). По сути, это равносильно добавлению дополнительного условияWHERE к каждому запросу пользователя к этой таблице.
Например, следующая политика ограничивает для analyst_role доступ только строками из ЕС:
SELECT * FROM db.orders возвращает те же строки, что и запрос SELECT * FROM db.orders WHERE region = 'EU'.
Предложение TO
В секции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
Допускается, чтобы для одной и той же таблицы и одного и того же пользователя одновременно было включено несколько политик. Поэтому нужен способ объединять условия из нескольких политик. По умолчанию политики объединяются с помощью булева оператораOR. Например, следующие политики:
peter видеть строки, где либо b=1, либо c=2.
Предложение AS указывает, как политики должны сочетаться с другими политиками. Политики могут быть либо разрешающими, либо ограничивающими. По умолчанию политики являются разрешающими, то есть они объединяются с помощью булева оператора OR.
В качестве альтернативы политику можно задать как ограничивающую. Ограничивающие политики объединяются с помощью булева оператора AND.
Вот общая формула:
access_control_improvements.users_without_row_policies_can_read_rows включен по умолчанию. Поэтому пользователь, к которому не применимо ни одно условие, видит все строки, а параметр access_control_improvements.throw_on_unmatched_row_policies, отключенный по умолчанию, вместо этого генерирует исключение, если для таблицы условия заданы, но ни одно из них не применимо.
Например, следующие политики:
peter видеть строки только при одновременном выполнении условий b=1 AND c=2.
Политики на уровне базы данных объединяются с политиками на уровне таблицы.
Например, следующие политики:
peter видеть строки таблицы table1 только при одновременном выполнении условий b=1 И c=2, хотя
для любой другой таблицы в mydb к пользователю применялась бы только политика b=1.
Таблицы, читающие данные из других таблиц
Политика ROW POLICY фильтрует строки там, где данные фактически читаются. ТаблицаAlias возвращает строки своей целевой таблицы как собственные, поэтому политики ROW POLICY целевой таблицы применяются и при чтении через псевдоним, объединяясь с политиками самого псевдонима через логическое AND. Таблица Merge применяет политики тех таблиц, из которых читает данные. Есть одно исключение: если подходящая таблица читает данные удалённо (например, таблица Distributed), удалённый сервер обрабатывает запрос до применения политики, поскольку политика выполняется поверх чтения этой таблицы, а не непосредственно при чтении. Такой запрос может завершиться ошибкой, если он выполняет агрегацию, не выбирая столбцы, используемые политикой, или вернуть меньше строк, чем допускает политика, если удалённый сервер применяет ORDER BY ... LIMIT к строкам, которые политика скрыла бы. В этом случае определяйте политику на базовых локальных таблицах каждого удалённого сервера.
Это правило действует не для всех таблиц, читающих данные из другой таблицы. Таблица Buffer и materialized view, чтение из которых идёт через таблицу назначения или целевую таблицу, не наследуют политики ROW POLICY этой таблицы: политика задаётся для схемы целевой таблицы, а для представления с SQL SECURITY DEFINER она вычисляется для другого пользователя, а не для того, кто выполняет чтение. В таких случаях определяйте политику на той таблице, к которой пользователи фактически обращаются с запросами.
Распределённые таблицы и таблицы с удалённым доступом к данным
ROW POLICY фильтрует строки там, где фактически читаются данные таблицы. Таблица, делегирующая чтение удалённым серверам, например таблица Distributed или обёртка над ней (например, materialized view с цельюDistributed), отправляет удалённым серверам только текст запроса и не может применить фильтр политики при удалённом чтении. Чтобы фильтр не был незаметно отброшен, запросы к такой таблице от пользователей, к которым применяется политика, отклоняются с ошибкой ILLEGAL_PREWHERE.
Вместо этого определите политику для базовых локальных таблиц на каждом удалённом сервере: она будет применяться там, когда переданный запрос читает эти таблицы:
Таблицы Join
Таблица Join — это заранее подготовленная хеш-таблица, которуюJOIN или joinGet считывают целиком, поэтому отфильтровать её строки при этом невозможно. Политика для такой таблицы, в том числе политика на уровне всей базы данных ON db.*, фильтрует обычный SELECT из таблицы, однако, пока она действует, запросы JOIN и joinGet к этой таблице завершаются ошибкой ACCESS_DENIED.
Предложение ON CLUSTER
Позволяет создавать политики строк в кластере, см. Distributed DDL. Это также удобный способ создать политику для локальных таблиц каждого сервера кластера.Примеры
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