Статьи

Управление контролем доступа в СУБД «Енисей»

В прошлом году одним из наиболее значимых изменений, сделанных в СУБД Енисей, был полностью переработанный механизм управления доступом. Но перед тем, как рассказать о нововведениях, давайте вспомним, как осуществлялось управление доступом ранее.
В каждой базе данных Енисея имеется специальный документ, который называется объектом безопасности и доступен по адресу
http://<SERVER_ADDRESS>/<DB_NAME>/_security
Данный документ перечисляет пользователей сервера, которые обладают правами доступа к указанной базе данных с полномочиями администратора, или рядового пользователя. Администраторы базы данных могут создавать и изменять проектные документы, а также менять объект безопасности. А рядовые пользователи могут читать, создавать и изменять обычные документы. Сразу заметим, что операция удаления документа тоже является одним из вариантов его изменения. Конечно, нет никакой необходимости перечислять персонально каждого из пользователей в объекте безопасности, вместо этого можно указывать роли пользователей.
Структура старого объекта безопасности:
{
“admins”: {
	“names”: [USER_NAME],
	“roles”: [ROLE_NAME]
},
“members”: {
	“names”: [USER_NAME],
	“roles”: [ROLE_NAME]
},
}
где:
USER_NAME - имя пользователя,
ROLE_NAME - наименование роли пользователей.
Проектирование новой модели управления доступом выполнялось с учетом соблюдения следующих требований:
  1. Одновременная поддержка дискреционной и мандатной модели контроля доступа.
  2. Контроль доступа на уровне отдельных документов, а не только целой БД.
  3. Раздельное управление доступом к операциям создания, обновления, чтения документов и проектных документов и к настройке контроля доступа.
Все эти требования являлись новыми для Енисея, ни одно из них в текущей схеме безопасности не обеспечивалось.

С точки зрения терминологии в управлении доступом различают объекты и субъекты доступа. В нашем случае объектами доступа выступают БД и документы в них, а субъектами - пользователи сервера или кластера Енисея.

Первый пункт в списке требований означает, что кроме перечисления пользователей и ролей, имеющих доступ к объектам, должен быть еще и второй механизм: объекты и субъекты доступа имеют специальный числовой атрибут, обозначающий уровень допуска. При этом, для успешного доступа уровень субъекта должен быть не ниже, чем уровень объекта доступа. И оба этих подхода должны функционировать совместно, дополняя друг друга. Второе требование говорит о том, что в одной и той же БД могут находиться документы с разными настройками доступа. А третье требование - что необходимо разграничивать операции чтения и записи объектов доступа. В предыдущем варианте управления доступом группа admins обладала правами одновременно и на обновление документов и на изменение настроек доступа, и было невозможно разделить доступ к данным операциям, т.е. если пользователь мог создать индекс в базе (индекс - это одна из возможных функций проектного документа), то он мог также и изменить состав администраторов этой БД.

Кроме того, данный состав требований отлично согласуется с нормативной документацией ФСТЭК, соблюдение требований которой нам будут необходимы при получении соответствующих сертификатов на Енисей.
Нагляднее всего основную идею изменений иллюстрирует новый состав атрибутов объекта безопасности БД:
{
"admins": ACCESS_GROUP,
"writers": ACCESS_GROUP,
"readers": ACCESS_GROUP,
"level": LEVEL
}
где
ACCESS_GROUP: {
           	"users": [USER_NAME],
           	"roles": [ROLE_NAME]
          	};
LEVEL - уровень допуска.
Из данной структуры видно, что на смену атрибута “members” пришли два других: “readers” и “writers”. Плюс к тому, добавлен еще один дополнительный атрибут “level”, характеризующий уровень допуска базы. Пользователи из категории “admins” могут менять данный объект безопасности, а также им доступны операции по созданию и изменению проектных документов. “readers” могут только читать обычные документы из БД, а “writers” - создавать, изменять и удалять документы. Уровень допуска можно рассматривать как уровень секретности документов в раритетных материальных архивах, но с более широким диапазоном возможных значений - любое неотрицательное целое число.

Кроме изменения в составе объекта безопасности БД, был также добавлен служебный атрибут “_level” в свойствах пользователя и опциональный служебный атрибут “_access” у каждого документа в БД, который служит объектом безопасности документа. Последнее изменение позволяет максимально гибко настраивать полномочия доступа в пределах одной базы, т.к. у каждого документа или проектного документа может быть свой персональный объект безопасности - свои читатели и редакторы.
Традиционно, в Енисее имена всех служебных атрибутов начинаются с символа подчеркивания.
Структура объекта безопасности документа или проектного документа (атрибут “_access”):
{
"writers": ACCESS_GROUP,
"readers": ACCESS_GROUP,
"level": LEVEL
}
Можно заметить, что отличием объекта безопасности документа от объекта безопасности БД является отсутствие в первом роли “admins”. То есть редактирование любых объектов безопасности доступно только администраторам БД (но с возможным дополнительным ограничением по уровню допуска). Таким образом, у нас получилось два вложенных уровня объектов безопасности - первый у БД и второй у документов. Данные объекты безопасности действуют вместе таким образом, что могут накладывать дополнительные ограничения, но не могут расширять доступ. Например, чтобы определенный пользователь мог прочесть данный документ, он также должен быть включен в состав читателей БД. Если у документа не определен объект безопасности, то действуют все настройки из объекта безопасности БД. Аналогичная картина и с уровнем допуска: уровень допуска документа не может быть ниже, чем уровень допуска у БД. Если объект безопасности документа (атрибут “_access” в документе) присутствует, но какая-то из категорий пользователей в нем пустая, то данной ролью не будет обладать никто.

Есть также особенная категория пользователей - администраторы сервера Енисея. Эти пользователи в силу того, что информация о них хранится в конфигурационных файлах, а не в реестре пользователей, не могут иметь никаких атрибутов - ни списка ролей, ни уровней допуска. Они являются супер-пользователями и имеют полный доступ к созданию, удалению, чтению и модификации любых баз и документов в них, включая изменение свойств безопасности (ролей и уровня допуска) любых других пользователей.

Более детально и формально все нюансы наличия или отсутствия доступа к различным операциям с базами и документами указаны в Матрице полномочий доступа. В ней перечислены объекты доступа, виды операций с этими объектами, а также роли пользователей, которым доступны данные операции. Для объектов доступа также указаны их краткие обозначения, которые используются и в наименовании ролей. Например, DB.admins - это пользователи, перечисленные в атрибуте “admins” объекта безопасности БД, а DDoc.readers - это пользователи из атрибута “readers” объекта безопасности проектного документа.
  • Объект/Операция
  • Создание
  • Обновление/Удаление
  • Чтение
  • Специфические операции
  • База данных (DB)
  • _
  • DB.admins
  • DB.admins, DB.readers
  • Уплотнение БД и представлений: DB.admins
  • Объект безопасности БД (DB._security)
  • NA
  • DB.admins
  • DB.admins, DB.readers
  • _
  • Проектный документ (DDoc)
  • DB.admins
  • DB.admins,DDoc.writers
  • DB.admins, DDoc.readers (DB.readers)
  • Выполнение функций: DB.admins, DDoc.readers (DB.readers)
  • Объект безопасности проектного документа (DDoc._access)
  • DB.admins
  • DB.admins
  • DB.admins, DDoc.readers (DB.readers)
  • _
  • Документ (Doc)
  • DB.admins, DB.writers
  • DB.admins, Doc.writers (DB.writers)
  • DB.admins, Doc.readers (DB.readers)
  • _
  • Объект безопасности документа (Doc._access)
  • DB.admins
  • DB.admins
  • DB.admins, Doc.readers (DB.readers)
  • _
Примечания:
  1. При создании объекта безопасности БД во всех списках пользователей указана только роль Server.admins (“_admin”). Уровень допуска устанавливается равным 0.
  2. Роли, которые указаны в скобках являются дополнительными и действуют, если не определены основные роли, указанные перед скобками. Например, Doc.readers (DB.readers) означает, что операция доступна пользователям из атрибута “readers” объекта безопасности документа, а если этот объект безопасности отсутствует, то пользователям “readers” из объекта безопасности БД.

Особенности управления доступом

Уровень допуска документа или проектного документа не может быть ниже, чем уровень допуска БД, в которой находится данный документ. Это контролируется Енисеем при создании или изменении документа. При невыполнении данного условия возвращается ошибка на запрос создания или изменения документа.

Объекты безопасности и уровень допуска всегда задают или модифицируют пользователи с полномочиями администратора БД. Администратор БД также обладает своим уровнем допуска. Администратор БД может указать уровень допуска для объекта выше, чем собственный уровень. Такая операция будет успешно выполнена, но в результате данный администратор БД потеряет доступ к объекту и не сможет модифицировать его в дальнейшем. Последующее изменение объекта будет доступно администраторам БД с более высоким уровнем допуска (равном или выше уровня допуска объекта), а также всем администраторам сервера.

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

При репликации реплицируются также и атрибуты “_access” документов. Таким образом, атрибут “_access”, если он определен в документе, всегда выдается в составе документа при запросе и не может быть скрыт каким-то образом.

UI редактирования свойств безопасности

Редактирование свойств пользователей теперь присутствует и в UI администрирования Енисея. Впрочем, оно функционально только для случая, когда реестр пользователей ведется в самом Енисее, а не во внешней системе, например в LDAP-каталоге.
Настройка объекта безопасности БД выполняется в UI администратора Енисея, так же как и ранее, но возможности редактирования теперь соответствуют новой модели контроля.

А настройка атрибута _access документов или проектных документов из UI в удобном виде не доступна, так же как и редактирование самого документа - только в виде прямого изменения JSON-контента документов, либо с помощью соответствующих API-методов.

Практические примеры работы механизма контроля доступа

Сервер Енисея запущен на локальной машине на стандартном порту, поэтому все запросы будут выполняться по адресу 127.0.0.1:5984.

Для целей эксперимента создадим несколько новых пользователей сервера:
Каждому пользователю назначена определенная роль, которая на текущий момент не имеет какого-либо смысла. Более того, роли в Енисее сами по себе не имеют никакой привязки к возможным операциям, они более соответствуют понятию просто групп в других системах. Обратите внимание, что у пользователей настроены разные уровни допуска.

Дальнейшие операции будем выполнять запросами к REST API с помощью утилиты curl, а не из UI администрирования. Команды будут выделены жирным шрифтом, чтобы отделить их от возвращаемых ответов. В запросах применяется Basic-авторизация: имя и пароль пользователя задаются явно в параметрах вызова curl, поэтому всегда становится наглядным, от имени какого из пользователей этот запрос выполнен.
1._Создадим новую база данных db1, при этом запрос выполним с реквизитами администратора сервера:
$ curl -u "admin:admin" -X PUT http://127.0.0.1:5984/db1
{"ok":true}
2._Вернем объект безопасности созданной БД (с форматированием вывода с помощью команды jq):
$ curl -u "admin:admin" -X GET http://127.0.0.1:5984/db1/_security | jq
{
  "admins": {
	"names": [],
	"roles": ["_admin"]
  },
  "readers": {
	"names": [],
	"roles": [“_admin"]
  },
  "writers": {
	"names": [],
	"roles": ["_admin"]
  },
  "level": 0
}
Видно, что во всех списках пользователей указана только роль “_admin”, которая соответствует администраторам севера. Следовательно, ни одному из наших новых пользователей сейчас не будет доступна никакая операция с базой. В базе на текущий момент нет документов, но попробуем запросить их, для примера, от имени “user1”:
curl -u "user1:user1" -i -X GET http://127.0.0.1:5984/db1/_all_docs
HTTP/1.1 403 Forbidden
Cache-Control: must-revalidate
Content-Length: 72
Content-Type: application/json
Date: Sun, 14 Jan 2024 11:01:03 GMT
Server: Yenisei/2.1.0-1328 (Erlang OTP/24)
X-Couch-Request-ID: b2ac7a74d0
X-CouchDB-Body-Time: 0

{"error":"forbidden","reason":"you are not allowed to access this db"}
3._Настроим доступ к db1, отредактировав объект безопасности. Администраторами БД укажем пользователей с ролью “manager”, редакторами - с ролью “editor”, а читателями - с ролью “client”:
curl -u "admin:admin" -X PUT http://127.0.0.1:5984/db1/_security
 -H "Content-Type: application/json"
 -d '{"admins": {"names": [], "roles": ["manager"]},
      "writers": {"names": [], "roles": ["editor"]},
      "readers": {"names": [], "roles": ["client", "editor"]},
      "level": 0}'
HTTP/1.1 200 OK

{"ok":true}
После этого “user1” уже должен суметь прочесть документы из БД, т.к. он имеет роль “editor”, которая перечислена в списке ролей атрибута “readers”:
curl -u "user1:user1" -i -X GET http://127.0.0.1:5984/db1/_all_docs
HTTP/1.1 200 OK

{"total_rows":0,"offset":0,"rows":[
]}
4._Создадим пару документов в базе под пользователем “user1”, который имеет на это полномочия в соответствии с объектом безопасности БД, идентификаторы новых документов “doc1” и “doc2”:
curl -u "user1:user1" -i -X POST http://127.0.0.1:5984/db1 -H "Content-Type: application/json" -d '{"_id": "doc1"}'
HTTP/1.1 201 Created

{"ok":true,"id":"doc1","rev":"1-967a00dff5e02add41819138abb3284d"}

curl -u "user1:user1" -i -X POST http://127.0.0.1:5984/db1 -H "Content-Type: application/json" -d '{"_id": "doc2"}'
HTTP/1.1 201 Created

{"ok":true,"id":"doc1","rev":"1-967a00dff5e02add41819138abb3284d"}
Такая же операция добавления документа от пользователя “user2” оканчивается ошибкой, т.к. этот пользователь может только читать документы, но не добавлять их:
curl -u "user2:user2" -i -X POST http://127.0.0.1:5984/db1 -H "Content-Type: application/json" -d '{"_id": "doc3"}'
HTTP/1.1 403 Forbidden

{"error":"forbidden","reason":"you are not authorized for this operation"}
Чтение документов пользователем “user2” работает успешно:
curl -u "user2:user2" -i -X GET http://127.0.0.1:5984/db1/doc1
HTTP/1.1 200 OK

{"_id":"doc1","_rev":"1-967a00dff5e02add41819138abb3284d"}
5._Теперь к документу “doc2”, добавим объект безопасности, в котором установим уровень допуска = 2, в результате чего не все пользователи с ролью “client” смогут его прочесть. Запрос выполняется от имени “user3”, который является администратором БД db1, а только администраторы могут настраивать контроль доступа:

curl -u "user3:user3" -i -X POST http://127.0.0.1:5984/db1
 -H "Content-Type: application/json"
 -d '{"_id":"doc2",
      "_rev":"1-967a00dff5e02add41819138abb3284d",
      "_access": {"readers": {"names": [], "roles": ["client", "editor"]},
      "writers": {"names":[], "roles": ["editor"]},
      "level": 2}}'
HTTP/1.1 201 Created

{"ok":true,"id":"doc2","rev":"2-c57ab28650ccc9789d299d9bd79a0c40"}
Чтение данного документа с этого момента доступно только пользователям с уровнем допуска не менее 2. Проверим это:
curl -u "user1:user1" -i -X GET http://127.0.0.1:5984/db1/doc2
HTTP/1.1 403 Forbidden

{"error":"forbidden","reason":"you are not authorized for this operation"}

curl -u "user4:user4" -i -X GET http://127.0.0.1:5984/db1/doc2
HTTP/1.1 200 OK

{"_id":"doc2","_rev":"2-c57ab28650ccc9789d299d9bd79a0c40","_access":{"readers":{"names":[],"roles":["client","editor"]},"writers":{"names":[],"roles":["editor"]},"level":2}}

Заключение

В последних версиях Енисея механика контроля доступа была существенно переработана. На смену довольно простому по своим возможностям алгоритму пришел действительно универсальный вариант, который может покрыть практически любые потребности целевых проектов. Управление безопасностью построено на полностью внутренне-согласованной модели, поддерживающей одновременно мандатное и дискреционное разграничение полномочий. При этом было увеличено количество контролируемых операций, в результате чего стало возможным, например, наделить некоторых пользователей доступом только на чтение документов. Поведение системы в целом имеет исчерпывающее формальное определение с помощью “Матрицы полномочий”, которая дает ответы на все вопросы, связанные с наличием или отсутствием доступа в той или иной комбинации ограничений, заданных в объектах безопасности баз данных и документов.

Контроль доступом доведен до уровня отдельных документов, что позволяет в пределах одной базы разграничить доступ к ним для разных групп пользователей. При этом описание полномочий выполняется в виде иерархии, в которой свойства безопасности подчиненных объектов дополняют заданные на более высоком уровне, внося дополнительные ограничения. Если проводить аналогию с реляционными СУБД, то для них это соответствует разграничению доступа на уровне отдельных строк.

Модель контроля доступа функционирует не только локально в пределах одного сервера или кластера Енисея, но также и при репликации данных между разными кластерами или серверами, то есть она продолжает успешно функционировать и при использовании Енисея в качестве транспортной инфраструктуры, обеспечивающей передачу всех видов трафика между отдельными компонентами распределенной целевой системы.
Юрий Пипченко
Архитектор СУБД Енисей
ООО “Эквирон”