InfraGuard

Роли, команды и ответственные

Роли и команды — только информационные подписи, доступ открывает исключительно уровень; а также объединённый селектор ответственного (пользователь или команда).

Обзор — что это даёт

Роли и команды — это информационные подписи для классификации людей. Единственное, что открывает доступ к экранам и действиям, — это уровень (user_level). Что пользователь видит и что ему разрешено сохранять или удалять, на 100 % определяется уровнем; роли («DBA», «DevOps», «Безопасность») и команды («Команда инфраструктуры», «Команда безопасности») — это теги для отображения и организационной структуры, они не дают никаких прав.

Так модель прав остаётся простой. Чтобы дать человеку права администратора, вы повышаете его уровень, а не меняете роль. Отметка «Безопасность» у пользователя не откроет экраны безопасности; его уровень должен быть Сотрудник (5) или выше.

В статье разобраны три вещи:

  1. Роли (infr_role) — шесть должностных подписей (DBA, DevOps, Безопасность, Администратор, Сотрудник, Разработчик).
  2. Команды (infr_team) — организационные единицы, используются для принадлежности пользователей и назначения ответственных за активы.
  3. Селектор ответственного — объединённый выпадающий список, в котором можно назначить либо пользователя, либо команду; его единственный источник истины — App\Support\Owners. Поле «ответственный» на экранах Инстансы, Оборудование и Хранилище использует именно его.

Управление доступом = только уровень (user_level). Роли и команды программно не открывают никаких прав. Об устройстве уровней см. Как устроены уровни (RBAC).

Когда это нужно

Структура экрана

/admin/users (Администрирование ▸ Пользователи и роли) содержит две вкладки.

Вкладка Содержимое
Пользователи Список пользователей (логин · имя · email · роль · команда · уровень · статус · последний вход) + CRUD в модальном окне
Команды Список команд (название · цвет · руководитель · описание · число участников) + CRUD в модальном окне

В модальном окне редактирования пользователя есть селекторы уровня / роли / команды, а под ними такая подсказка:

Уровень определяет доступ — Демо (чтение), Сотрудник (работа), Администратор (всё). Роль — только подпись.

Как пользоваться

Роли — должностные подписи

Справочник ролей состоит из шести записей, которые InfrRoleSeeder идемпотентно записывает через upsert по key.

key Подпись Токен цвета seq
dba DBA info 10
devops DevOps accent 20
security Безопасность crit 30
admin Администратор warn 40
staff Сотрудник muted 50
developer Разработчик good 60

Роль admin (подпись «Администратор») не имеет никакого отношения к уровню администратора (10). Роль — всего лишь подпись, поэтому пользователь с ролью «Администратор», но уровнем Демо (1), не сможет ничего сохранить. И наоборот: администратор с уровнем 10 получает всё администрирование даже с пустой ролью.

Команды — организационные единицы

Команды свободно создаются и изменяются на вкладке Команды. Четыре команды из сидера:

Название Цвет Описание
Команда инфраструктуры accent Эксплуатация серверов / сети / хранилищ
Команда безопасности crit Обнаружение · реагирование · блокировка
Команда разработки good Разработка сервисов · развёртывание
Команда DBA info Эксплуатация баз данных · тюнинг

Поля редактирования команды:

Поле Значение
Название (name) Обязательно. Название команды
Цвет (color) Оттенок бейджа (accent/crit/good/info/muted …)
Руководитель (lead_user_id) Один пользователь (необязательно)
Описание (description) Произвольный текст
Активна (is_active) Неактивные команды скрыты в селекторе ответственного

Селектор ответственного — пользователи и команды вместе

У активов (серверные инстансы, оборудование, хранилища) есть поле «ответственный», в котором может быть как человек, так и команда. Правила этого объединённого селектора находятся в App\Support\Owners (SOT).

Форма хранения = два столбца

Таблица актива хранит ответственного в двух столбцах.

Столбец Значение
owner_id Целочисленный первичный ключ пользователя или команды
owner_type 'user' или 'team'

Форма обмена на фронтенде = одна строка ref

Браузер (формы, фильтры) обменивается owner_type и owner_id как одной строкой.

user:5     → user id 5
team:3     → team id 3

Начальные варианты (Owners::options()) возвращают две группы для отрисовки optgroup (кэш на 20 секунд). Закрытые пользователи (is_close=1) и неактивные команды (is_active=0) исключаются.

{
  "users": [ { "ref": "user:5", "id": 5, "name": "Jane Doe" } ],
  "teams": [ { "ref": "team:3", "id": 3, "name": "Infra Team" } ]
}

Разбор и сборка на стороне сервера

Помощник Поведение
Owners::split($ref) "user:5" → ['user', 5]. Неверный формат → ['user', 0] (= не назначен)
Owners::ref($ownerId, $ownerType) (5, 'user') → "user:5". Пустой ownerId → null
Owners::resolveName($ownerId, $ownerType) Отображаемое имя для карточек и списков (null, если его нет, кэш на 20 секунд)
Owners::flush() Сбросить кэш после изменений пользователей или команд

Например, контроллер сохранения инстанса делает так:

// ref ответственного ("user:5"/"team:3") → owner_id + owner_type
[$ownerType, $ownerId] = Owners::split($request->input('owner_ref'));
$payload['owner_id']   = $ownerId ?: null;
$payload['owner_type'] = $ownerId ? $ownerType : 'user';   // по умолчанию 'user', если не задано

Тот же ref используется и при фильтрации по ответственному — запрос списка разбирает параметр owner (user:5/team:3) через split() и сужает выборку до WHERE owner_id = ? AND owner_type = ?.

Селектор ответственного в неизменном виде переиспользуется на экранах активов Инстансы, Оборудование и Хранилище и файлы. Назначение команды ответственной ставит на линию ответственности всю команду (это устойчиво к уходу любого одного человека).

Аватар · инициалы · цвет

Аватар рядом с подписью генерирует RolePolicy по имени.

Источники данных

Таблица Назначение
infr_role Справочник ролей (6 информационных подписей) — key·name·color·seq·is_active
infr_team Справочник команд — name·color·lead_user_id·description·is_active·seq
users Пользователи — user_level (определяет доступ), role_id (допускает null), team_id (допускает null)
таблицы активов Ответственный хранится в двух столбцах owner_id + owner_type (user/team) (Инстансы/Оборудование/Хранилище и др.)

Помощники SOT:

Права доступа

Предохранители (защита последнего администратора)

Ситуация Результат
Понизить / отключить / удалить последнего активного администратора Отклонено — «Последнего активного администратора нельзя понизить, отключить или удалить.»
Понизить или отключить собственный уровень администратора Отклонено — «Нельзя понизить или отключить собственный доступ администратора.»
Удалить самого себя Отклонено — «Нельзя удалить самого себя.»
Логин уже используется Отклонено — «Этот логин уже используется.»

Диагностика и частые вопросы

В. Я выдал человеку роль «Безопасность», но экраны безопасности не открываются. Роли — это подписи, они не открывают прав. Экранам безопасности (в основном на чтение) нужен уровень — поднимите его до Сотрудника (5) или выше. См. Уровни RBAC.

В. В выпадающем списке ответственных не хватает какого-то пользователя или команды. Закрытые пользователи (is_close=1) и неактивные команды (is_active=0) исключаются из селектора. Активируйте пользователя или команду заново, а если список устарел — дождитесь истечения кэша на 20 секунд (Owners::flush() сбрасывает его немедленно).

В. Если удалить команду, исчезнут ли её люди? Нет. Пользователи остаются; только их team_id становится null (без команды). Ссылка актива owner_type='team' существует отдельно, поэтому актив тоже не удаляется (просто отображение ответственного станет пустым).

В. Я сохранил ответственного, но имя не отображается. У resolveName() кэш на 20 секунд. Если вы только что что-то переименовали, значение обновится в ближайшее время. Также проверьте, что формат ref — user:5/team:3: сломанный формат split() трактует как «не назначен» (user:0).

В. Может ли у пользователя быть две роли? Нет. role_id — одиночное значение (допускающее null). Если нужна ещё и организационная группировка, используйте команду (тоже одиночное значение).

Смежные темы

사용자 · 팀 관리
사용자 · 팀 관리