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
.
Документация по использованию данных утилит доступна в руководстве администратора МСВСфера ОС в главе «logging-security».
Как и в случае с ролью администратора средства виртуализации, для
предоставления прав на запуск этих команд с полномочиями администратора будет
реализован через утилиту 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',
]);