Выпуск 16 · подкаст «Тысяча фичей»

#16: Спэшл: RBAC

13:12
↓ скачать mp3

Первый «спэшл» — короткий тематический выпуск между основными. Александр разбирает модель управления доступом Role-Based Access Control (RBAC): три её кита (пользователи, роли, привилегии), надстройки в виде иерархии ролей и ограничений (разделение обязанностей и лимиты на назначение ролей), а затем на пальцах сравнивает реализации в Postgres (где путаются пользователи и роли) и ClickHouse (с хорошей иерархией привилегий, но возможностью выдавать их и пользователям напрямую — что ломает каноническую модель).

Главное

  • RBAC строится на трёх сущностях — пользователи, роли, привилегии — и двух связях: «роль — привилегия» (permission assignment) и «пользователь — роль» (role assignment).
  • Главное преимущество RBAC — контроль доступа на уровне ролей: право выдаётся и отзывается один раз у роли, а не у каждого пользователя; один `REVOKE` на роль закрывает доступ всем её носителям.
  • Плоская модель (flat RBAC) расширяется иерархией: роли наследуют друг друга, поэтому вместо назначения нескольких ролей одному пользователю заводят агрегирующую роль (например, `Manager`).
  • Ограничения (constrained RBAC) дают разделение обязанностей — например, запрет совмещать роли `Admin` и `QA` у одного пользователя.
  • Ограничением может быть любой предикат, включая лимит на число носителей роли: если самую мощную роль разрешено выдать лишь двоим, при взломе злоумышленник не сможет её присвоить.
  • Ориентир «правильного» RBAC — модель из статей NIST (с 1996 года): реализация должна быть простой и не добавлять того, чего в стандарте нет.
  • В Postgres нет чёткого разделения пользователей и ролей (роль с `LOGIN`/`NOLOGIN`, `CREATE ROLE` в SQL против `createuser` в shell) — понятия смешиваются, хотя в остальном система гибкая, вплоть до row-level security.
  • ClickHouse хорошо иерархирует привилегии (`ALTER` → `ALTER TABLE` → `ALTER COLUMN` → …), но позволяет назначать привилегии и ролям, и пользователям напрямую — что нарушает каноническую RBAC-модель.
Расшифровка

[00:18] Всем привет! Меня зовут Саша Пахомов, а это «спэшл». Да, я решил разнообразить контент и выпускать такие специальные выпуски по четвергам. Они будут не такими регулярными, как основные (те выходят раз в две недели по понедельникам), — скорее зависящие от настроения, от погоды, от моего желания поделиться чем-то, что не укладывается в основной подкаст и не тянет на самостоятельный выпуск.

[00:48] Сегодня я хотел бы поговорить про Role-Based Access Control — это то, чем я занимаюсь на работе в последнее время. Тема мне кажется интересной, но в полноценный выпуск такую небольшую тему не вынести, да и не всем она зайдёт. Но кому интересно — присоединяйтесь. Поехали!

[01:21] Итак, поговорим о модели Role-Based Access Control, или попросту РБАК, как я буду называть её дальше. Сорян, если кого-то это будет напрягать, но я её именно так проговариваю в голове. Думаю, каждый из вас так или иначе сталкивался с этим понятием — когда выдавал (или просил выдать) гранты и права пользователям в каком-нибудь Postgres, другой базе данных или, например, в Hadoop. Любому программисту с более-менее приличным опытом эта модель знакома.

[01:41] Давайте немного погрузимся в определение — более строгое, чуть ли не математическое. Заодно поймём, почему большинство современных систем, которые заявляют, что реализуют RBAC, на самом деле реализуют его лишь частично — а то и вовсе ломают модель, так что это уже не RBAC, а что-то другое. И об этом они, как правило, не говорят. Для меня это большой вопрос: то ли разработчики не осознают, что делают не то, то ли это осознанно — чтобы не смущать пользователей.

[02:42] Итак, RBAC — распространённый подход к контролю доступа, прав и безопасности внутри баз данных (и не только — вообще внутри систем). В основе модели три больших понятия, три кита: пользователи (users), роли (roles) и права — permissions или privileges, кто как называет. Как правило, эти сущности есть везде: в Postgres есть роли, пользователи и привилегии, в ClickHouse — тоже. Во всех системах, которые заявляют про RBAC, они присутствуют. Это база.

[03:26] Связи между этими сущностями тоже имеют названия. Первая — permission assignment, то есть связь «роль — право» (роль — привилегия). Вторая — role assignment (user assignment): это когда мы ассоциируем пользователей с ролями. Пользователи — это любые агенты: люди, сервисные аккаунты, всё, что пытается взаимодействовать с системой. Роли — сущности с говорящими названиями вроде Admin или System Manager, которые агрегируют в себе набор прав. А привилегии (permissions) — это как раз те права, разрешения и гранты, которые выдаются ролям, чтобы те получали доступ к объектам.

[04:19] Разберём на примере. Я хочу получить доступ к таблице Users. У меня пользователь с ролью Dev, а у этой роли по умолчанию нет привилегии на чтение из Users. Я иду к администратору: «дай моей роли Dev доступ к Users». Он выполняет что-то вроде GRANT SELECT, UPDATE ON Users TO Dev — и теперь все пользователи, ассоциированные с ролью Dev, получают доступ к таблице. Вот так работает эта модель.

[05:02] В чём преимущество? Контроль над доступом реализован на уровне ролей: мы абстрагируемся от конкретных пользователей и как администраторы работаем с ролями. Выдали всем разработчикам роль Dev — у них появилась общая сущность. А когда мы вдруг решаем, что разработчикам не стоит иметь доступ к какой-то таблице (например, к аудит-логам — вдруг кто-то случайно её дропнет), мы не бежим по всем аккаунтам с REVOKE, а работаем с ролью: один REVOKE на роль — и ни один разработчик больше не может читать и писать в эту таблицу. В этом и прелесть — есть такое разграничение.

[06:06] Но то, что я описал, в литературе называется flat RBAC — плоская модель. Плоская, потому что в ней нет надстроек, которыми многие пользуются. Первая надстройка — наследование ролей, так называемая иерархическая RBAC-модель: роли могут наследоваться друг от друга. Чем удобно? Если есть роли на базы данных A, B и C, а нам нужен менеджер с доступом ко всем трём, мы не назначаем ему три роли по очереди, а заводим роль Manager, которая наследует те три, — и наследуем пользователя уже от неё. Это даёт гибкость в настройке прав.

[06:58] Следующая надстройка — constraints, ограничения (constrained RBAC). Например, мы хотим разделить административные и пользовательские роли: тот, кто раздаёт гранты, не должен сам делать селекты. Вводим ограничение: роль Admin не может сочетаться с остальными ролями. И когда мы попытаемся назначить одному пользователю и Admin, и, скажем, QA, система откажет: «нельзя, есть ограничение». Это называется разделением ответственности (separation of duties) — тоже полезная функция.

[07:53] Ограничивать можно не только сочетания ролей — по сути, любой предикат. Распространённый пример — ограничение на количество пользователей, которым можно назначить конкретную роль. Скажем, самую мощную роль Admin разрешаем только двоим — CTO и реальному админу, — и больше никому. Тогда при взломе злоумышленник не сможет просто так заполучить эту роль и наназначать своих пользователей, чтобы выкачивать данные: больше двух нельзя, система не позволит. Тоже удобное свойство.

[08:37] Так вот, последнюю неделю я изучал RBAC — посмотрел с десяток баз данных, у кого как реализована модель. И, честно говоря, ни в одной не нашёл реализацию, которая бы мне понравилась. А критерии простые: во-первых, модель должна быть простой; во-вторых, действительно следовать RBAC в том виде, в каком он с 1996 года описан в статьях NIST — фактическом отраслевом стандарте, — не добавляя ничего, чего там нет. Таких систем на слуху я почти не нашёл.

[09:21] Взять Postgres. Проблема в том, что там нет чёткого разделения на пользователей и роли. Эксперты по Postgres сейчас возразят: «можно роль с NOLOGIN, а можно с LOGIN». Технически да, но по факту даже в SQL команда называется CREATE/DROP ROLE, а в shell — createuser/dropuser: то есть понятия смешиваются на уровне команд. Мне как пользователю это некомфортно — я не понимаю, чем они отличаются. Возможно, разработчик Postgres придёт и пояснит, что я лох и всё различается вот так и вот так. Но если мне, инженеру с приличным опытом, сложно понять разницу — наверное, что-то не то в самой модели, а не в том, что я тупой. В остальном Postgres гибкий — есть даже row-level security (политики доступа на уровне строк), — но настраивается это с некоторыми приседаниями: система большая, старая, и без легаси не обошлось.

[10:50] А вот где легаси нет — я смотрел в сторону ClickHouse — там уже видно, что сделано получше. На уровне привилегий всё хорошо иерархировано: есть привилегия ALTER, под ней ALTER TABLE, под ней — ALTER UPDATE, ALTER DELETE, ALTER COLUMN, а у ALTER COLUMN ещё подуровень вроде DROP, MODIFY, COMMENT. Куча древовидных отношений между привилегиями, и они хорошо описаны: когда вы выдаёте привилегию на роль, вы даёте не всё поддерево, а только нужный уровень. В общем, можно почитать документацию — там всё понятно.

[11:40] Но в чём косяк ClickHouse по отношению к моему идеальному RBAC-миру? В том, что там можно назначать привилегии и на роли, и на пользователей напрямую. По сути, это ломает модель: каноническое определение RBAC говорит, что пользователям назначают только роли, а роли получают привилегии. А здесь — «да, но ещё и привилегии можно на юзеров». Тогда мой пример с гибким контролем на уровне ролей ломается: доступы появляются и на уровне пользователей, и становится непонятно, что тогда роль, а что пользователь, — начинается смешение. Может, это практическое требование — удобно навесить привилегию на пользователя напрямую, а не гонять через роли. Не знаю; ещё покопаюсь, поразбираюсь — возможно, придётся с этим согласиться. Но пока вот такой изъян я нашёл.

[12:38] В остальном же, пусть и с жирным минусом, RBAC в ClickHouse реализован неплохо. Вот такая она — одновременно и простая, и не очень — модель RBAC. Надеюсь, вам было хоть чуть-чуть полезно и интересно.