---
metadata:
  - name: generator
    content: Diplodoc Platform v5.50.6
alternate:
  - https://ytsaurus.tech/docs/en/user-guide/storage/row-level-security.md
  - https://ytsaurus.tech/docs/ru/user-guide/storage/row-level-security.md
---
> **Documentation Index:** Fetch the complete configuration index at https://ytsaurus.tech/docs/ru/llms.txt

<!-- source: ru/_includes/user-guide/storage/row-level-security.md -->
# Управление доступом к строкам таблиц

В данном разделе содержится описание работы Row-Level Security (RLS), приводятся примеры использования.

## Краткое описание { #brief_desc }

Row-Level Security (RLS) позволяет уточнить правила доступа к отдельным строкам таблицы на основе предикатов, вычисляемых на данных строк. Это позволяет хранить в одной таблице как общедоступные данные, так и приватные и определять доступы через произвольные выражения на [языке запросов](https://ytsaurus.tech/docs/ru/user-guide/dynamic-tables/dyn-query-language.md) YTsaurus.

## Принцип работы { #details }

Общие принципы работы системы контроля доступа в системе YTsaurus описаны в разделе [Контроль доступа](https://ytsaurus.tech/docs/ru/user-guide/storage/access-control.md).

Чтобы установить RLS, необходимо в ACL узлов использовать ACE специального вида, в которых указан дополнительный атрибут `row_access_predicate`. Подобные ACE никак не участвуют в обычных проверках прав к целым объектам. Такие ACE учитываются на стадии проверки доступа к отдельным строкам таблиц.

Выражение `row_access_predicate` должно вычисляться в булево значение. Выражение может ссылаться на любые колонки из схемы таблицы и использовать стандартные операторы и функции.

Предположим, что система выполняет проверку прав доступа на чтение к таблице `T` от имени пользователя `U`. Подобные чтения происходят при выполнении команды `read-table`, а также при подаче таблицы `T` в качестве входной в операцию MapReduce или другие.

Помимо наличия права `read` на всю таблицу у пользователя также должен выполняться хотя бы один предикат доступа к строкам для каждой строки, которую он хочет прочитать.

Последнее свойство проверяется следующим образом: построим эффективный ACL таблицы `T`. Из составляющих его ACE отберем те, которые являются строчными (содержат атрибут `row_access_predicate`) и применимы к пользователю `U` (`U` либо явно упомянут в `subjects`, либо принадлежит к одной из групп, упомянутых в `subjects`). Обозначим результат через `L`.

В случае, если `L` пусто, это означает, что для таблицы `T` и пользователя `U` никакие строчные разрешения не действуют, и пользователь не сможет прочитать ни одной строки (за исключением случая, когда у него есть право `full_read`).

В противном случае, если нашлась хотя бы одна подходящая ACE, для каждой строки в таблице хотя бы один предикат из `L` должен вычисляться в `true`, чтобы пользователь мог прочитать эту строку.

## Режим совместимости { #compatibility_mode }

Если установить на таблицу строчный ACL, то у пользователей, у которых нет права `full_read`, возникнет ошибка авторизации при попытке чтения таблицы.

Для того, чтобы пользователь явно понимал, что может получить не все данные, необходимо указывать специальный флаг `omit_inaccessible_rows` (значение по умолчанию `%false`) при операциях чтения. В CLI используйте `--omit-inaccessible-rows` с командами `read` или `read-table`. Одноименная настройка также имеется в спецификации операций.

В случае, если данная опция включена, то при отсутствии доступа на чтение к какой-либо строке таблицы (при наличии доступа на чтение к таблице в целом) система скрывает строку полностью от пользователя, а запрашиваемое действие при этом завершается успешно.

## Ограничения и особенности

RLS не поддерживается для динамических таблиц. Любая попытка чтения будет возвращать ошибку.

В силу динамичности правил доступа, не всегда система может эффективно выполнить те или иные действия. Например, количество данных, прочитанных с диска, не всегда пропорционально числу доступных строк. Но динамичность влияет не только на скорость, но и на некоторые API:

1. `row_index`, указанные в `ranges` в команде `read-table`, считают индексы относительно строк, записанных на диск, а не строк, доступных пользователю. Например, если запросить первые 100 строк (`read-table //path/to/table[:#100]`), при этом не имея доступа ни к одной из этих строк, вернётся пустой результат.
2. Аналогично, в операциях поверх таблиц, которые пользователь не может читать полностью, `row_index` указывать нельзя.

Выражение, указываемое в `row_access_predicate`, должно быть выражением, зависящим исключительно от значений в строке. В нём нельзя использовать `JOIN`, `GROUP BY`, текущего пользователя. Также нельзя использовать QL UDFs.

### Утечка информации через метаданные

В момент вычисления предиката игнорируются ограничения доступа к колонкам (см. [Управление доступом к колонкам таблиц](https://ytsaurus.tech/docs/ru/user-guide/storage/columnar-acl.md)). Поскольку доступом управляет владелец данных, это не является уязвимостью как таковой, однако может привести к утечке данных на основе различных метаданных, поэтому необходимо проявлять аккуратность в проектировании предикатов.

Кроме того, даже если ограничений на колонки нет, по метаданным всё равно можно получить информацию, которая может оказаться секретной.

Разберём игрушечный пример:
Пусть в таблице лежат две строчки и есть такой ACE:
```
{
    action = allow;
    subjects = [vasya];
    permissions = [read];
    row_access_predicate = "region != 'RU' or income < 1000";
}
```
Вася читает таблицу и видит лишь одну строчку. Из этого можно сделать вывод, что для оставшейся строчки предикат не выполняется, а значит для неё выполняется `region = 'RU' and income >= 1000`. Является ли эта информация секретной и возможна ли вообще (пример намеренно игрушечный, в реальных условиях в таблице скорее всего будет лежать больше строк), остаётся на усмотрение владельца данных.


## Пример { #example }

Пусть на таблице установлен ACL, в котором есть следующая ACE:

```bash
{
    action = allow;
    subjects = [username];
    permissions = [read];
    row_access_predicate = "user_id = 12345";
}
```

Будем также считать, что на всем пути вверх до корня от данной таблицы более нет никаких строчных ACE.

Тогда выполняется следующее:

1. Любой пользователь, у которого есть доступ `read` на данную таблицу, по умолчанию не сможет прочитать ни одной строки. Однако, такой пользователь сможет прочитать атрибуты таблицы.

2. Пользователь `username` сможет прочитать только те строки, где колонка `user_id` равна `12345` (при условии, что у него также есть доступ `read` на таблицу целиком).

3. Если пользователь попытается прочитать строки без флага `omit_inaccessible_rows`, то возникнет ошибка авторизации.

## Право полного чтения { #full_read }

Право `full_read` даёт возможность читать всю таблицу полностью, вне зависимости от других ACE с `row_access_predicate`. Такое право необходимо для некоторых действий, которые либо работают на уровне control plane, либо не интерпретируют (а соответственно, не распаковывают блоки данных) строчки. Такими действиями являются команды `copy`, `concatenate`, `move`, а также операция `RemoteCopy`.

Примечание: тривиальный предикат (выражение, всегда возвращающее `true`) не эквивалентен `full_read`. Поскольку в общем случае проверка доступа ко всем строкам требует прочтения всех строк, YTsaurus не делает никаких попыток проверить, является ли предикат тривиальным. Симметрично, при наличии всегда-ложного предиката, система будет вынуждена прочитать все строки таблицы и для каждой проверить, возвращает ли предикат false.

## Замечания { #notes }

{% note warning "Внимание" %}

Установка строчной ACE ограничивает доступ к строкам для всех пользователей, не соответствующих предикату. Поэтому, прежде чем ограничивать доступ на уровне строк, убедитесь, что подобные действия не приведут к поломке процессов, работающих с таблицей.

{% endnote %}

1. В текущей реализации функциональность распространяется лишь на чтение строк. Поэтому не нужно указывать в атрибуте `permissions` права, отличные от `read`.
2. В предикате можно использовать только те колонки, которые есть в схеме.
3. Построчные ACE наследуются стандартным образом, и их наследование, в частности, обрывается в тех узлах, где выставлено `inherit_acl = %false`.
4. Если в эффективном ACL таблицы есть ACE, в котором выражение некорректно (например, ссылается на несуществующую колонку, возвращаемый тип отличается от boolean, складывает число и строку), то любая операция чтения будет возвращать ошибку. Для того, чтобы этого избежать, рекомендуется выставлять подобные ACE только в тех директориях, в которых все таблицы имеют гомогенную схему.
5. Для того, чтобы протестировать предикат, можно воспользоваться операцией Merge с `input_query`, поместив выражение после ключевого слова `WHERE`. Оба механизма используют одинаковый синтаксис для выражений, поэтому результат работы операции будет совпадать с тем, какие строки увидит пользователь, на которого действует соответствующий ACE.
6. Управление строчными ACE доступно только администраторам YTsaurus.
<!-- endsource: ru/_includes/user-guide/storage/row-level-security.md -->
