14.13. Реализация ролевой модели управления доступом
14.13.1. Введение
В этом разделе описывается способ реализации ролевой модели управления доступом к функциям гипервизора.
Для средства виртуализации ОС должны быть реализованы четыре роли:
разработчик виртуальной машины;
администратор безопасности средства виртуализации;
администратор средства виртуализации;
администратор виртуальной машины.
В данном примере для реализации ролевой модели будут использоваться стандартные группы пользователей GNU/Linux. Соответственно, для назначения пользователю той или иной роли, системный администратор должен будет добавить пользователя в соответствующую роли группу или несколько групп, если пользователь выполняет несколько ролей.
14.13.2. Роль администратора средства виртуализации
Роль администратора средства виртуализации должна позволять:
создавать учётные записи пользователей средства виртуализации;
управлять учётными записями пользователей средства виртуализации;
назначать права доступа пользователям средства виртуализации к виртуальным машинам;
создавать и удалять виртуальное оборудование средства виртуализации;
изменять конфигурации виртуального оборудования средства виртуализации;
управлять доступом виртуальных машин к физическому и виртуальному оборудованию;
управлять квотами доступа виртуальных машин к физическому и виртуальному оборудованию;
управлять перемещением виртуальных машин;
удалять виртуальные машины;
запускать и останавливать виртуальные машины;
создавать снимки состояния виртуальных машин, включающих файл конфигурации виртуальной машины, образа виртуальной машины и образа памяти виртуальной машины.
Назовём соответствующую группу пользователей libvirt-admin и создадим её:
$ sudo groupadd --system libvirt-admin
Для работы с гипервизором libvirt используются системные учётные записи,
соответственно, для реализации первых двух функций потребуется предоставить
группе право на выполнение следующих команд:
/usr/sbin/useradd— добавляет новую учётную запись пользователя, позволяет назначить пользователю группы и установить пароль;/usr/sbin/usermod— позволяет модифицировать учётную запись пользователя: заблокировать её, изменить домашний каталог, командную оболочку, изменить набор пользовательских групп и т.д.;/usr/sbin/userdel— удаляет учётную запись пользователя;/usr/bin/passwd— устанавливает пароль для учётной записи пользователя;/usr/bin/gpasswd— позволяет управлять группами пользователей: добавлять или удалять участников, ограничить доступ к группе и т.д.;/usr/bin/chage— устанавливает срок действия учётной записи и пароля пользователя.
Для предоставления группе libvirt-admin прав на запуск данных команд с
правами администратора будет использоваться утилита sudo. Создайте файл
/etc/sudoers.d/libvirt-fstec следующего содержания:
# запретить участникам группы libvirt-admin вызов любых команд
%libvirt-admin ALL=(ALL) !ALL
# разрешить участникам группы libvirt-admin вызов перечисленных команд. При
# этом команда sudo попросит ввести пароль текущего пользователя для
# авторизации.
%libvirt-admin ALL=/usr/sbin/useradd, /usr/sbin/usermod, \
/usr/sbin/userdel, /usr/bin/passwd, /usr/bin/gpasswd, /usr/bin/chage
# если требуется использовать перечисленные команды без пароля, то вместо
# предыдущей строки используйте следующую:
# %libvirt-admin ALL=NOPASSWD: /usr/sbin/useradd,
# /usr/sbin/usermod, /usr/sbin/userdel, /usr/bin/passwd, /usr/bin/gpasswd, /usr/bin/chage
Установите для созданного файла соответствующие права доступа и владельца:
$ sudo chown root:root /etc/sudoers.d/libvirt-fstec
$ sudo chmod 440 /etc/sudoers.d/libvirt-fstec
Теперь перейдём к остальным функциям, перечисленным в техническом задании для
роли администратора средства виртуализации. Для их реализации потребуется
предоставить этой роли полный доступ ко всем API-вызовам гипервизора, для этого
потребуется реализовать соответствующую polkit политику:
// объявляем переменную, значением которой будет название группы пользователей,
// для которой реализуется роль администратора средства виртуализации
libvirtAdminGroup = 'libvirt-admin';
// метод addRule объекта polkit добавляет новое правило в политику управления
// доступом.
// Правила реализуются в виде функций, принимающих два аргумента:
// action — действие, для которого выполняется проверка;
// subject — информация о процессе, который запрашивает разрешение на
// выполнение действия. Среди прочей информации объект subject содержит
// идентификатор процесса (PID), имя пользователя, от которого был запущен
// процесс и список групп, в которые входит этот пользователь.
// По результатам проверки функция должна вернуть одно из следующих значений:
// polkit.Result.YES — разрешить доступ;
// polkit.Result.NO — запретить доступ;
// polkit.Result.AUTH_SELF — запросить авторизацию от имени пользователя,
// запустившего сессию, и предоставить доступ в случае успеха;
// polkit.Result.AUTH_SELF_KEEP — то же самое, что и AUTH_SELF, но авторизация
// сохраняется (кешируется) на короткий промежуток времени;
// polkit.Result.AUTH_ADMIN — запросить авторизацию от имени пользователя с
// правами администратора и предоставить доступ в случае успеха;
// polkit.Result.AUTH_ADMIN_KEEP — аналогично AUTH_ADMIN, но авторизация
// сохраняется (кешируется) на короткий промежуток времени;
// polkit.Result.NOT_HANDLED — указывает на то, что данная функция не
// осуществляет запрошенную проверку. В таком случае polkit запустит
// проверку следующего правила. Это также является поведением по
// умолчанию, если функция не вернула ничего.
polkit.addRule(function(action, subject) {
// действие org.libvirt.unix.manage запрашивается при подключении к
// локальному Unix сокету гипервизора libvirt
if (action.id == 'org.libvirt.unix.manage') {
// разрешить доступ без пароля для всех пользователей, включённых в
// группу администраторов средства виртуализации
if (subject.isInGroup(libvirtAdminGroup)) {
return polkit.Result.YES;
}
// запретить доступ для всех остальных пользователей
else {
return polkit.Result.NO;
}
}
// данное правило обрабатывает только события, связанные с API-вызовами
// гипервизора libvirt
else if (action.id.indexOf('org.libvirt.api.') != 0) {
return polkit.Result.NOT_HANDLED;
}
// разрешить выполнение любого действия org.libvirt.api.* пользователям в
// группе администраторов средства виртуализации
if (subject.isInGroup(libvirtAdminGroup)) {
return polkit.Result.YES;
}
// запретить выполнение действий всем остальным пользователям
return polkit.Result.NO;
});
Сохраните код политики в файл /etc/polkit-1/rules.d/99-libvirt-fstec.rules и
установите для него корректные права:
$ sudo chown root:root /etc/polkit-1/rules.d/99-libvirt-fstec.rules
$ sudo chmod 644 /etc/polkit-1/rules.d/99-libvirt-fstec.rules
Служба polkit автоматически загрузит и применит обновлённые правила.
В совокупности с правилами для sudo данная политика позволяет роли
администратора средства виртуализации выполнять все требуемые операции за
исключением предоставления прав доступа пользователям средства виртуализации к
виртуальным машинам — подход к реализации этого требования будет описан в конце
этой главы.
Для назначения роли администратора средства виртуализации необходимо добавить
пользователя в ранее созданную группу libvirt-admin:
# замените user на реальное имя пользователя
$ sudo gpasswd -a user libvirt-admin
Если пользователь уже вошёл в систему, то необходимо либо выйти и зайти заново, либо выполнить от его имени команду:
$ newgrp libvirt-admin
После этого пользователь получит соответствующие роли полномочия. В следующих разделах политика доступа к API гипервизора будет доработана.
14.13.3. Роль администратора виртуальной машины
Роль администратора виртуальной машины должна позволять осуществлять доступ пользователя средства виртуализации к виртуальной машине посредством интерфейса средства виртуализации.
По сути это означает возможность подключения к графической или терминальной
сессии виртуальной машины используя утилиты virt-manager, virsh console или
virt-viewer.
Назовём соответствующую группу пользователей libvirt-user и создадим её:
$ sudo groupadd --system libvirt-user
Для подключения к сессии виртуальной машины команды virt-manager и
virsh console используют API гипервизора libvirt, ниже представлен
минимально необходимый набор разрешений:
connect.getattr— подключение к API гипервизора и получение информации о системе;connect.read— получение информации об узле гипервизора;connect.search-domains— получение списка доступных виртуальных машин (используется утилитойvirt-managerи командойvirsh list);domain.getattr— получение списка виртуальных машин;domain.read— получение информации о виртуальной машине;domain.read-secure— чтение настроек виртуальной машины, связанных с безопасностью (используется утилитой virt-manager);domain.open-device— подключение к каналам, последовательным и параллельным портам виртуальной машины. Данное разрешение требуется для подключения к последовательному терминалу (serial console).domain.open-graphics— подключение к «аппаратному» графическому терминалу виртуальной машины (virt-manager --show-domain-console);
для предоставления этих разрешений группе libvirt-user потребуется внести
соответствующие изменения в политику polkit:
libvirtAdminGroup = 'libvirt-admin';
// объявляем переменную, значением которой будет название группы пользователей,
// для которой реализуется роль администратора (пользователя) виртуальных машин
libvirtUserGroup = 'libvirt-user';
// список разрешений libvirt API для роли пользователя виртуальных машин
libvirtUserActions = [
'connect.getattr',
'connect.read',
'connect.search-domains',
'domain.getattr',
'domain.read',
'domain.read-secure',
'domain.open-device',
'domain.open-graphics'
];
polkit.addRule(function(action, subject) {
if (action.id == 'org.libvirt.unix.manage') {
// разрешить подключение к API гипервизора через Unix сокет группам,
// указанным в переменных libvirtAdminGroup и libvirtUserGroup
if (subject.isInGroup(libvirtAdminGroup)
|| subject.isInGroup(libvirtUserGroup)) {
return polkit.Result.YES;
} else {
return polkit.Result.NO;
}
} else if (action.id.indexOf('org.libvirt.api.') != 0) {
return polkit.Result.NOT_HANDLED;
}
// заменить префикс libvirt API org.libvirt.api на пустую строку чтобы не
// приходилось его дублировать в списке разрешённых действий. Таким образом
// действие org.libvirt.api.connect.read преобразуется в connect.read.
var api = action.id.replace('org.libvirt.api.', '');
if (subject.isInGroup(libvirtAdminGroup)) {
return polkit.Result.YES;
}
// разрешить действие пользователю из группы libvirtUserGroup, если это
// действие перечислено в списке libvirtUserActions
else if (subject.isInGroup(libvirtUserGroup)
&& libvirtUserActions.includes(api)) {
return polkit.Result.YES;
}
return polkit.Result.NO;
});
Кроме команд virt-manager и virsh console для подключения к виртуальным
машинам также может использоваться команда virt-viewer, которая, в отличии
от двух других, подключается к виртуальной машине по протоколам VNC/SPICE без
использования API libvirt. Соответственно, для ограничения возможности такого
подключения администратор средства виртуализации должен либо отключить
поддержку протоколов VNC/SPICE, либо установить пароль для подключения и
предоставить его только тем пользователям, которые должны иметь возможность
такого подключения.
14.13.4. Роль разработчика виртуальной машины
Роль разработчика виртуальной машины должна позволять:
создавать виртуальные машины;
изменять конфигурации виртуальных машин.
Назовём соответствующую данной роли группу пользователей libvirt-vm-dev и
создадим её:
$ sudo groupadd --system libvirt-vm-dev
Как уже было рассмотрено ранее, основным способом создания виртуальных машин в
среде виртуализации ОС МСВСфера является использование команды virt-install.
Полный список доступных для использования в политиках polkit разрешений
libvirt доступен в разделе «14.12.3. Объекты и разрешения libvirt»,
а ниже представлен минимальный набор разрешений, необходимый для корректной
работы команды virt-install:
connect.getattr— подключение к API гипервизора и получение информации о системе;connect.read— получение информации об узле гипервизора;connect.search-storage-pools— получение списка доступных пулов хранения;domain.getattr— получение списка виртуальных машин;domain.read— получение информации о виртуальной машине;domain.save— изменение конфигурационного файла виртуальной машины;domain.start— запуск виртуальной машины;domain.write— изменение виртуальной машины;network.getattr— получение списка сетей;network.read— чтение настроек сети;network-port.create— создание сетевого порта;network-port.delete— удаление сетевого порта;network-port.read— получение информации о сетевом порте;storage-pool.getattr— получение списка пулов хранения;storage-pool.read— получение информации о пуле хранения;storage-pool.refresh— обновление списка томов хранения в пуле;storage-pool.search-storage-vols— получение списка томов хранения в пуле;storage-vol.create— создание тома хранения;storage-vol.getattr— получение списка томов в пуле хранения;storage-vol.read— получение информации о пуле хранения.
Однако, с вышеперечисленным набором функциональность будет крайне ограничена:
будет невозможно использовать графическую утилиту для создания и настройки виртуальных машин
virt-manager;функции выключения и перезагрузки виртуальной машины будут недоступны;
в случае ошибки при создании виртуальной машины утилита
virt-installне сможет автоматически удалить созданный в процессе том хранения.
Для решения вышеперечисленных проблем рекомендуется добавить следующие разрешения роли разработчика виртуальной машины:
domain.init-control— перезагрузка или выключение виртуальной машины;domain.read-secure— чтение настроек виртуальной машины, связанных с безопасностью (используется утилитойvirt-manager);domain.open-device— подключение к каналам, последовательным и параллельным портам виртуальной машины. Данное разрешение требуется для подключения к последовательному терминалу (serial console).domain.open-graphics— подключение к «аппаратному» графическому терминалу виртуальной машины (virt-manager --show-domain-console);connect.search-domains— получение списка доступных виртуальных машин (используется утилитойvirt-managerи командойvirsh list);connect.search-networks— получение списка доступных сетей (функция доступных сетей вvirt-managerи работа командыvirsh net-list);storage-vol.delete— удаление тома хранения. Является необходимым для автоматической очистки, если операция по созданию виртуальной машины завершилась с ошибкой.
Создав группу пользователей и определившись с необходимыми разрешениями для
доступа к API libvirt, доработаем политику polkit чтобы предоставить
необходимые полномочия группе:
libvirtAdminGroup = 'libvirt-admin';
// объявляем переменную, значением которой будет название группы пользователей,
// для которой реализуется роль разработчика виртуальных машин
libvirtVMDevGroup = 'libvirt-vm-dev';
libvirtUserGroup = 'libvirt-user';
libvirtUserActions = [
'connect.getattr',
'connect.read',
'connect.search-domains',
'domain.getattr',
'domain.read',
'domain.read-secure',
'domain.open-device',
'domain.open-graphics'
];
// список разрешений libvirt API для роли разработчика виртуальных машин. За
// основу берётся список разрешений для пользователя чтобы избежать
// дублирования кода
libvirtVMDevActions = libvirtUserActions.concat([
'connect.search-storage-pools',
'connect.search-networks',
'domain.init-control',
'domain.save',
'domain.start',
'domain.write',
'network.getattr',
'network.read',
'network-port.create',
'network-port.delete',
'network-port.read',
'storage-pool.getattr',
'storage-pool.read',
'storage-pool.refresh',
'storage-pool.search-storage-vols',
'storage-vol.create',
'storage-vol.delete',
'storage-vol.getattr',
'storage-vol.read'
]);
polkit.addRule(function(action, subject) {
if (action.id == 'org.libvirt.unix.manage') {
// разрешить подключение к API гипервизора через Unix сокет группам,
// указанным в переменных libvirtAdminGroup, libvirtVMDevGroup и
// libvirtUserGroup
if (subject.isInGroup(libvirtAdminGroup)
|| subject.isInGroup(libvirtVMDevGroup)
|| subject.isInGroup(libvirtUserGroup)) {
return polkit.Result.YES;
} else {
return polkit.Result.NO;
}
} else if (action.id.indexOf('org.libvirt.api.') != 0) {
return polkit.Result.NOT_HANDLED;
}
var api = action.id.replace('org.libvirt.api.', '');
if (subject.isInGroup(libvirtAdminGroup)) {
return polkit.Result.YES;
}
// разрешить действие пользователю из группы libvirtVMDevGroup если это
// действие перечислено в списке libvirtVMDevActions
else if (subject.isInGroup(libvirtVMDevGroup)
&& libvirtVMDevActions.includes(api)) {
return polkit.Result.YES;
}
else if (subject.isInGroup(libvirtUserGroup)
&& libvirtUserActions.includes(api)) {
return polkit.Result.YES;
}
return polkit.Result.NO;
});
На этом реализацию роли разработчика виртуальных машин можно считать завершённой.
14.13.5. Роль администратора безопасности средства виртуализации
Роль администратора безопасности средства виртуализации должна позволять:
иметь доступ на чтение к журналу событий безопасности средства виртуализации;
формировать отчёты с учетом заданных критериев отбора, выгрузку (экспорт) данных из журнала событий безопасности средства виртуализации.
Для работы с журналом событий безопасности пользователю достаточно иметь права на запуск следующих утилит от имени суперпользователя:
/usr/sbin/ausearch— утилита для поиска событий в журналах безопасности службыauditd;/usr/sbin/aureport— утилита для построения отчётов о событиях безопасности на основе журналов безопасности службыauditd.
Документация по использованию данных утилит доступна в руководстве администратора в главе «6. Регистрация событий безопасности».
Как и в случае с ролью администратора средства виртуализации, для
предоставления прав на запуск этих команд с полномочиями администратора будет
реализован через утилиту sudo.
Группа пользователей, выполняющих роль администратора безопасности средства
виртуализации будет называться libvirt-sec-admin, создадим её:
$ sudo groupadd --system libvirt-sec-admin
Далее, добавьте в файл /etc/sudoers.d/libvirt-fstec следующие настройки
(вероятно, вам потребуется использовать либо редактор visudo, либо временно
изменить права доступа к файлу, поскольку ранее мы установили их в режим только
для чтения владельцем и группой — 440):
# запретить участникам группы libvirt-sec-admin вызов любых команд
%libvirt-sec-admin ALL=(ALL) !ALL
# разрешить участникам группы libvirt-sec-admin вызов команд /usr/sbin/ausearch
# и /usr/sbin/aureport. При этом команда sudo попросит ввести пароль текущего
# пользователя для авторизации.
%libvirt-sec-admin ALL=/usr/sbin/ausearch, /usr/sbin/aureport
# если требуется использовать команды /usr/sbin/ausearch и /usr/sbin/aureport
# без пароля, то вместо предыдущей строки используйте следующую:
# %libvirt-sec-admin ALL=NOPASSWD: /usr/sbin/ausearch, /usr/sbin/aureport
Если для редактирования вы изменяли права доступа к файлу, то восстановите исходные значения:
$ sudo chown root:root /etc/sudoers.d/libvirt-fstec
$ sudo chmod 440 /etc/sudoers.d/libvirt-fstec
Далее, добавьте пользователя, который будет выполнять роль администратора
безопасности средства виртуализации в группу libvirt-sec-admin:
# замените "user" на реальное имя пользователя
$ sudo gpasswd -a user libvirt-sec-admin
Если пользователь уже вошёл в систему, то необходимо либо выйти и зайти заново, либо выполнить от его имени команду:
$ newgrp libvirt-sec-admin
Теперь пользователь сможет работать с журналом безопасности используя команды
sudo ausearch и sudo aureport.
Если вы хотите предоставить группе libvirt-sec-admin права на чтение
файлов журналов службы аудита напрямую, то в конфигурационном файле
/etc/audit/auditd.conf необходимо установить значение опции log_group
равным имени группы:
log_group = libvirt-sec-admin
И подать службе auditd сигнал перечитать конфигурационный файл:
$ sudo auditctl --signal reload
После этого права на файлы журналов в каталоге /var/log/audit поменяются с
-rw-------. 1 root root на -rw-r-----. 1 root libvirt-sec-admin:
$ sudo ls -la /var/log/audit/
drwxr-x---. 2 root libvirt-sec-admin 4096 окт 15 03:30 .
drwxr-xr-x. 16 root root 4096 ноя 20 11:16 ..
-rw-r-----. 1 root libvirt-sec-admin 5994208 ноя 20 18:59 audit.log
Таким образом пользователи, входящие в группу libvirt-sec-admin, получат
возможность выполнять чтение файлов журналов аудита.
Если вам требуется предоставить пользователю доступ к журналам systemd,
допустим, для просмотра логов Polkit или гипервизора Libvirt, то вы можете
добавить пользователя в системную группу systemd-journal, которая
предоставляет такую возможность:
# замените "user" на реальное имя пользователя
$ sudo gpasswd -a user systemd-journal
После этого пользователь получит возможность просматривать системные журналы
с помощью команды journalctl.
14.13.6. Регистрация событий запуска и остановки виртуальных машин
Одной из важных особенностей гипервизора libvirt, работающего в системном режиме (см. «14.3.3. Системный режим»), является
то, что в системном журнале событий безопасности службы auditd инициатором
всех событий, связанных с запуском или остановом виртуальных машин, является
пользователь root:
type=VIRT_CONTROL msg=audit(1733316312.117:1249): pid=10098 \
uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:virtd_t:s0-s0:c0.c1023 \
msg='virt=kvm op=stop reason=shutdown vm="msvsphere-9-server" \
uuid=9faaa743-e098-4925-8c4e-8854b88e7a25 vm-pid=0 exe="/usr/sbin/virtqemud" \
hostname=? addr=? terminal=? res=success'
Соответственно, из системного журнала невозможно узнать какой конкретно пользователь изменил состояние виртуальной машины.
Однако, для решения этой задачи можно применить политику polkit.
Реализуем следующую функцию, которая будет выводить название и идентификатор
виртуальной машины, а также имя пользователя, который вызвал изменение
состояния виртуальной машины через API:
function logVMActions(action, subject, api) {
var vmName = action.lookup('domain_name');
var vmUUID = action.lookup('domain_uuid');
var actionText;
switch(api) {
case 'domain.delete':
actionText = 'deletion';
break;
case 'domain.init-control':
actionText = 'reboot or shutdown';
break;
case 'domain.start':
case 'domain.stop':
actionText = api.split('.')[1];
break;
case 'domain.save':
case 'domain.write':
actionText = 'modification';
break;
}
if (actionText) {
polkit.log(`virtual machine "${vmName}" (UUID="${vmUUID}") ${actionText} initiated by "${subject.user}" user`);
}
}
И добавим вызов этой функции перед возвратом из функции, осуществляющей проверку прав доступа:
polkit.addRule(function(action, subject) {
if (action.id == 'org.libvirt.unix.manage') {
if (subject.isInGroup(libvirtAdminGroup)
|| subject.isInGroup(libvirtVMDevGroup)
|| subject.isInGroup(libvirtUserGroup)) {
return polkit.Result.YES;
} else {
return polkit.Result.NO;
}
} else if (action.id.indexOf('org.libvirt.api.') != 0) {
return polkit.Result.NOT_HANDLED;
}
var api = action.id.replace('org.libvirt.api.', '');
var result = polkit.Result.NO;
if (subject.isInGroup(libvirtAdminGroup)) {
result = polkit.Result.YES;
} else if (subject.isInGroup(libvirtVMDevGroup)
&& libvirtVMDevActions.includes(api)) {
result = polkit.Result.YES;
} else if (subject.isInGroup(libvirtUserGroup)
&& libvirtUserActions.includes(api)) {
result = polkit.Result.YES;
}
// вызвать функцию логирования изменения состояния виртуальной машины в
// случае предоставления доступа к API
if (result == polkit.Result.YES) {
logVMActions(action, subject, api);
}
return result;
});
Теперь при каждом изменении состояния или конфигурации виртуальной машины
в журнал службы polkit (journalctl -u polkit) будет попадать соответствующее
сообщение:
дек 04 15:47:40 msvsphere-94-arm.msvsphere.test polkitd[961]: \
<no filename>:189: virtual machine "msvsphere-9-server" \
(UUID="9faaa743-e098-4925-8c4e-8854b88e7a25") start initiated by "virtadmin" user
Теперь, получив идентификатор виртуальной машины из журнала auditd можно будет
узнать по нему какие пользователи выполняли те или иные действия с этой
виртуальной машиной.
14.13.7. Ограничение прав доступа к виртуальным машинам
Гипервизор libvirt, используемый в ОС МСВСфера, не предоставляет готового
решения для проблемы ограничения прав доступа к виртуальным машинам, поскольку
каждая организация использует свои правила и политики доступа.
Однако, поскольку для реализаций политик polkit используется язык
программирования JavaScript, не составляет труда реализовать практически
любую логику внутри политики.
Рассмотрим практическую реализацию на простом примере: предположим, что в
организации существуют два отдела, которые используют виртуальные машины —
разработчики приложений и тестировщики. Сотрудникам из отдела разработки
нужно предоставить доступ ко всем виртуальным машинам, имя которых начинается
с префикса dev-, а тестировщикам — ко всем виртуальным машинам, имя которых
начинается с qa-.
Для каждого отдела создадим соответствующую группу и добавим туда всех сотрудников:
# создаём группу для разработчиков devs и добавляем туда пользователей devuser1
# и devuserN
$ sudo groupadd -U devuser1,devuserN devs
# создаём группу для тестировщиков qa и добавляем туда пользователей qauser1 и
# qauserN
$ sudo groupadd -U qauser1,qauserN qa
Не забудьте добавить пользователей в группу libvirt-user чтобы
предоставить им права на подключения к виртуальным машинам.
Теперь реализуем функцию для проверки доступа к виртуальным машинам:
function checkUserVMAccess(action, subject) {
// сохраняем название виртуальной машины в переменную
var vmName = action.lookup('domain_name');
// если имя не определено, то разрешаем доступ — будут применяться
// ограничения роли
if (!vmName) {
return true;
}
// если название виртуальной машины начинается с "dev-" и пользователь
// входит в группу devs, то разрешаем доступ
if (vmName.startsWith('dev-') && subject.isInGroup('devs')) {
return true;
}
// если название виртуальной машины начинается с "qa-" и пользователь
// входит в группу qa, то разрешаем доступ
else if (vmName.startsWith('qa-') && subject.isInGroup('qa')) {
return true;
}
// запрещаем доступ в остальных случаях
return false;
}
И включим эту функцию в общую логику проверки для роли пользователя виртуальных машин:
polkit.addRule(function(action, subject) {
if (action.id == 'org.libvirt.unix.manage') {
if (subject.isInGroup(libvirtAdminGroup)
|| subject.isInGroup(libvirtVMDevGroup)
|| subject.isInGroup(libvirtUserGroup)) {
return polkit.Result.YES;
} else {
return polkit.Result.NO;
}
} else if (action.id.indexOf('org.libvirt.api.') != 0) {
return polkit.Result.NOT_HANDLED;
}
var api = action.id.replace('org.libvirt.api.', '');
var result = polkit.Result.NO;
if (subject.isInGroup(libvirtAdminGroup)) {
result = polkit.Result.YES;
} else if (subject.isInGroup(libvirtVMDevGroup)
&& libvirtVMDevActions.includes(api)) {
result = polkit.Result.YES;
}
// разрешить пользователю доступ к виртуальной машине если проверка ролевых
// полномочий завершилась успешно и функция checkUserVMAccess вернула true
else if (subject.isInGroup(libvirtUserGroup)
&& libvirtUserActions.includes(api)
&& checkUserVMAccess(action, subject)) {
result = polkit.Result.YES;
}
if (result == polkit.Result.YES) {
logVMActions(action, subject, api);
}
return result;
});
В результате применения новой политики обычные пользователи средства виртуализации получат доступ к виртуальной машине только в следующих случаях:
пользователь входит в группы
libvirt-userиdevs, название виртуальной машины начинается с префиксаdev-;пользователь входит в группы
libvirt-userиqa, название виртуальной машины начинается с префиксаqa-.
Для пользователей, входящих в группы libvirt-admin (администратор средства
виртуализации) и libvirt-vm-dev (разработчик виртуальных машин), дополнительные
ограничения применяться не будут.
14.13.8. Итоговая реализация в ОС МСВСфера
Описанная выше реализация ролевой модели на базе политик polkit поставляется
в RPM-пакете libvirt-fstec. Перед его установкой вам необходимо включить
драйвер контроля доступа polkit в настройках гипервизора — данная процедура
описана в разделе «14.12.2.1. Включение драйвера контроля доступа polkit».
После включения поддержки polkit установите пакет libvirt-fstec с помощью
следующей команды:
$ sudo dnf install -y libvirt-fstec
Пакет создаст в вашей системе группы libvirt-vm-dev, libvirt-admin,
libvirt-user, libvirt-sec-admin и файл /etc/sudoers.d/libvirt-fstec,
содержащий описанные в этой главе правила sudo для реализации ролевой модели.
Так же в каталоге /etc/polkit-1/rules.d будут созданы следующие файлы:
97-libvirt-fstec-vars.rules— в этом файле объявляются названия групп, соответствущие ролям, а также список действий, разрешённых для ролей разработчика и пользователя виртуальной машины.99-libvirt-fstec.rules— реализация правил для контроля доступа к APIlibvirt.
Вам, как системному администратору, потребуется самостоятельно создать файл
/etc/polkit-1/rules.d/98-libvirt-user-rules и определить в нём собственную
реализацию описанных ранее в этой главе функций logVMActions и
checkUserVMAccess, соответствующую политике безопасности вашего предприятия
и решаемой задаче. Реализация ролевой модели управления доступом сознательно
разделена на несколько файлов, чтобы вы могли вносить изменения, не нарушая при
этом целостность файлов RPM-пакета libvirt-fstec.
В качестве стартовой точки вы можете создать файл /etc/polkit-1/rules.d/98-libvirt-user-rules
следующего содержания:
function logVMActions(action, subject, api) {
var vmName = action.lookup('domain_name');
var vmUUID = action.lookup('domain_uuid');
var actionText;
switch(api) {
case 'domain.delete':
actionText = 'deletion';
break;
case 'domain.init-control':
actionText = 'reboot or shutdown';
break;
case 'domain.start':
case 'domain.stop':
actionText = api.split('.')[1];
break;
case 'domain.save':
case 'domain.write':
actionText = 'modification';
break;
}
if (actionText) {
polkit.log(`virtual machine "${vmName}" (UUID="${vmUUID}") ${actionText} initiated by "${subject.user}" user`);
}
}
function checkUserVMAccess(action, subject) {
// в этой функции вам необходимо реализовать собственные правила проверки
// доступа к виртуальной машине для пользователей средства виртуализации
return true;
}
И доработать функцию checkUserVMAccess по своему усмотрению.
В случае необходимости, используя файл 98-libvirt-user-rules вы также можете
предоставить пользователям дополнительные права доступа к API-вызовам
гипервизора, например:
libvirtUserActions.push(...[
'domain.start',
'network.getattr',
'network.read',
'network-port.create',
'network-port.delete',
'network-port.read',
]);