Polkit – это фреймворк авторизации, установленный в каждом современном дистрибутиве Linux: он предоставляет API, позволяющие привилегированным приложениям предоставлять сервисы непривилегированным субъектам.
Общение с Polkit происходит по шине D-Bus, которая представляет собой систему IPC (Interprocess Comunication); чтобы понять, как работает первая, нужно сначала разобраться, как реализована вторая.
В этом руководстве мы поговорим о Polkit, посмотрим, как он работает и как использовать утилиты, поставляемые вместе с ним в Linux.
Polkit и D-Bus
Прежде чем начать разговор о Polkit и выяснить его роль в современных операционных системах на базе Linux, необходимо понять, как работает D-Bus.
D-Bus – это шина сообщений, используемая для взаимодействия между процессами.
Некоторые сервисы регистрируются на шине и предоставляют информацию и функциональные возможности в виде свойств, сигналов и методов.
Каждый пользовательский сеанс получает свою сеансовую шину; сервисы, зарегистрированные на ней, запускаются с привилегиями пользователя.
Общесистемные сервисы, потенциально работающие от имени root, регистрируются на системной шине: они предлагают функции, требующие административных привилегий, например, монтирование файловой системы.
Такие утилиты, как d-feet (GTK) или QDBusViewer (QT), позволяют нам визуализировать сервисы, зарегистрированные на существующих шинах.
Обе утилиты отображают сервисы, зарегистрированные на шине, в левой колонке (например, org.freedesktop.Accounts), и путь к объектам, с которыми они поставляются, в правой (например, /org/freedesktop/Accounts).
Каждый объект предоставляет один или несколько интерфейсов, которые выступают в качестве пространств имен для методов, сигналов и свойств.
Как работает Polkit
Polkit зарегистрирован на “системной” шине D-Bus с именем org.freedesktop.PolicyKit1.
Служба запускается не от имени root, а с привилегиями пользователя polkitd и группы polkitd (см. /usr/lib/systemd/system/polkit.service).
Polkit не нужно запускать от имени root, потому что он сам не выполняет привилегированных действий: он просто проверяет, авторизован ли субъект для доступа к сервису, или механизму, в терминологии Polkit.
Иногда, чтобы разрешить доступ к сервису, Polkit может запросить у субъекта аутентификацию от своего имени или от имени администратора.
Для этого используется агент Polkit. Polkit поставляется с базовым агентом, называемым pkttyagent; все основные среды рабочего стола, однако, предоставляют свою собственную реализацию агента.
GNOME, например, поставляется с пакетом “polkit-gnome”, KDE включает “polkit-kde” и т. д.
Агент запускается автоматически вместе с пользовательской сессией и работает с привилегиями пользователя.
Приведенная ниже диаграмма, взятая со страницы freedesktop polkit, кратко описывает принцип работы polkit:
Как Polkit решает, авторизован ли субъект для доступа к определенному сервису и требуется ли аутентификация? Как видно на диаграмме выше, он опирается в основном на две вещи: политики и правила. Давайте рассмотрим их.
Polkit actions
Экшенс ( действия ) Polkit определяются в XML-файлах с расширением “.policy” в каталоге /usr/share/polkit-1/actions.
Ранее мы уже упоминали службу org.freedesktop.Accounts; действия, связанные с ней, определяются в файле /usr/share/polkit-1/actions/org.freedesktop.accounts.policy.
Здесь мы приводим определение одного из них в качестве примера:
<action id="org.freedesktop.accounts.change-own-user-data"> <description>Change your own user data</description> <message>Authentication is required to change your own user data</message> <defaults> <allow_any>yes</allow_any> <allow_inactive>yes</allow_inactive> <allow_active>yes</allow_active> </defaults> </action>
Действие определяется внутри тегов “action” и идентифицируется с помощью атрибута “id”.
Идентификатор используется для ссылки на действие из кода или из пользовательских правил Polkit (см. ниже).
Например, сервис org.freedesktop.Accounts ссылается на действие org.freedesktop.accounts.change-own-user-data, когда мы отправляем запрос на изменение данных нашего пользователя либо через панель настроек нашего любимого окружения рабочего стола, либо путем прямого вызова dbus с помощью приложения dbus-send.
С помощью тега “description” мы даем краткое описание действия, а с помощью тега “message” определяем сообщение, которое выводится субъекту при запросе на аутентификацию.
Поведение действия по умолчанию задается внутри тегов “default”, с помощью тегов “allow_any”, “allow_inactive” и “allow_active”.
Для чего они нужны?
Polkit способен различать активных и неактивных клиентов и соответствующим образом корректировать свое поведение.
🖧 Почему сайты сканируют мои порты?
Теги “allow_active” и “allow_inactive” используются для активных и неактивных клиентов на локальных консолях или графических дисплеях, а тег “allow_any” становится актуальным во всех остальных ситуациях, например, при удаленных соединениях по SSH или VNC.
Содержимое, разрешенное в этих тегах, следующее:
- no: пользователь не авторизован в действии
- yes: пользователь авторизован на действие без необходимости аутентификации
- auth_self: для авторизации пользователю необходимо пройти аутентификацию как самому себе (со своим паролем)
- auth_self_keep: то же самое, что и auth_self, но пароль запоминается
- auth_admin: пользователь должен пройти аутентификацию как root, чтобы быть авторизованным в действии
- auth_admin_keep: то же, что и auth_admin, но пароль запоминается
В определении действия, приведенном выше, во всех случаях используется “да”.
Именно по этой причине, хотя изменение пользователя – это действие, требующее привилегий root, мы можем, например, изменить свой пароль из панели настроек нашей любимой среды рабочего стола без необходимости аутентификации для повышения привилегий.
Тег, который не встречается в этом примере, – это “annotate”: он используется для предоставления дополнительных пар ключ-значение для действия.
Наиболее известными аннотациями являются:
- org.freedesktop.policykit.exec.path: это связано с использованием утилиты pkexec, см. ниже.
- org.freedesktop.policykit.imply: используется для определения “мета” действий. Принимает строку, содержащую разделенный пробелами список идентификаторов действий. Если пользователь авторизован для этого действия, то он будет авторизован и для этих действий.
- org.freedesktop.policykit.owner: принимает разделенный пробелами список записей PolkitIdentity (например, “unix-user:1000”), который определяет, кто может запрашивать, авторизован ли клиент на выполнение действия: обычно используется для демонов, запущенных не от имени root.
Правила Polkit
В дополнение к неявным действиям Polkit ищет правила, которые могут использоваться для определения более тонких политик.
Правила, предоставляемые производителями, устанавливаются в каталог /usr/share/polkit-1/rules.d: их нельзя изменять на месте, так как они могут быть отменены обновлениями системы.
Пользовательские правила хранятся в каталоге /etc/polkit-1/rules.d.
Правила пишутся с помощью Javascript в файлах с расширением “.rules”.
Вот пример правила, установленного средой рабочего стола GNOME в файле /usr/share/polkit-1/rules.d/gnome-control-center.rules:
polkit.addRule(function(action, subject) { if ((action.id == "org.freedesktop.locale1.set-locale" || action.id == "org.freedesktop.locale1.set-keyboard" || action.id == "org.freedesktop.ModemManager1.Device.Control" || action.id == "org.freedesktop.hostname1.set-static-hostname" || action.id == "org.freedesktop.hostname1.set-hostname" || action.id == "org.gnome.controlcenter.datetime.configure") && subject.local && subject.active && subject.isInGroup ("wheel")) { return polkit.Result.YES; } });
Метод addRule объекта polkit используется для добавления функции, которая вызывается при обращении к определенному действию.
В качестве аргумента метод принимает функцию.
Эта функция принимает два аргумента: “действие” и “субъект”.
Это два объекта, представляющие соответственно задействованное действие и субъекта, выполнившего запрос.
Правила устанавливают, что если идентификатор действия, доступ к которому осуществляется через свойство id объекта action, является одним из “org.freedesktop.locale1.set-locale”, “org.freedesktop.locale1.set-keyboard”, “org.freedesktop.ModemManager1.Device.Control”, “org.freedesktop.hostname1.set-static-hostname”, “org. freedesktop.hostname1.set-hostname” и “org.gnome.controlcenter.datetime.configure”, субъект находится в локальной и активной сессии и входит в unix-группу “wheel” (это эквивалент группы sudo в системах на базе debian), то он будет авторизован без необходимости аутентификации.
Это происходит благодаря возвращаемому значению: polkit.Result.YES.
Возвращаемые значения эквивалентны значениям, которые мы видели ранее в определениях действий, и организованы в словарь:
polkit.Result = { NO : "no", YES : "yes", AUTH_SELF : "auth_self", AUTH_SELF_KEEP : "auth_self_keep", AUTH_ADMIN : "auth_admin", AUTH_ADMIN_KEEP : "auth_admin_keep", NOT_HANDLED : null };
Чтобы перезаписать правило, определенное в каталоге /usr/share/polkit-1/rules.d, мы можем создать файл с таким же именем в каталоге /etc/polkit-1/rules.d.
Правила в обоих каталогах обрабатываются в лексическом порядке, но если в обоих каталогах существуют два файла правил с одинаковыми именами, то приоритет имеет тот, который находится в каталоге /etc/polkit-1/rules.d.
Существуют и другие методы, доступные для объекта “polkit”, кроме addRule. Другой часто используемый метод – addAdminRule.
Этот метод имеет ту же сигнатуру, что и addRule, но вызывается всякий раз, когда требуется аутентификация в качестве администратора.
Он используется для указания того, какие идентификаторы могут проходить аутентификацию в качестве администратора. В большинстве случаев метод используется, как в примере ниже, для включения членов группы “wheel”:
polkit.addAdminRule(function(action, subject) { return ["unix-group:wheel"]; });
Утилиты Polkit
Три утилиты командной строки включены в любую установку Polkit: “pkaction”, “pkcheck” и “pkexec”.
Давайте кратко рассмотрим, для чего они могут быть использованы.
pkaction
Утилита pkaction может использоваться для получения подробной информации о зарегистрированном действии Polkit.
Когда утилита вызывается без каких-либо аргументов или опций, она отображает все зарегистрированные действия:
Вот выдержка из результатов выполнения команды на стандартной установке Fedora Workstation:
[...] org.freedesktop.login1.attach-device org.freedesktop.login1.chvt org.freedesktop.login1.flush-devices org.freedesktop.login1.halt org.freedesktop.login1.halt-ignore-inhibit org.freedesktop.login1.halt-multiple-sessions org.freedesktop.login1.hibernate org.freedesktop.login1.hibernate-ignore-inhibit org.freedesktop.login1.hibernate-multiple-sessions org.freedesktop.login1.inhibit-block-idle org.freedesktop.login1.inhibit-block-shutdown org.freedesktop.login1.inhibit-block-sleep org.freedesktop.login1.inhibit-delay-shutdown org.freedesktop.login1.inhibit-delay-sleep org.freedesktop.login1.inhibit-handle-hibernate-key org.freedesktop.login1.inhibit-handle-lid-switch org.freedesktop.login1.inhibit-handle-power-key org.freedesktop.login1.inhibit-handle-reboot-key org.freedesktop.login1.inhibit-handle-suspend-key [...]
Чтобы получить подробную информацию о действиях, а не только их названия, мы можем вызвать утилиту с опцией –verbose.
Чтобы сфокусироваться на конкретном действии, мы передаем его имя в качестве аргумента –action-id.
Вот пример, в котором задействовано действие org.freedesktop.login1.halt:
Вот вывод, который мы получим:
pkcheck
Утилита pkcheck используется для проверки того, авторизован ли процесс на выполнение определенного действия, предоставляемого сервисом в системе dbus.
По сути, эта утилита представляет собой способ командной строки для вызова метода CheckAuathorization, предоставляемого интерфейсом polkit D-Bus.
Процесс может быть идентифицирован по имени системной шины или путем передачи таких деталей, как его PID, время запуска и uid.
Для использования последней стратегии мы передаем эти данные в качестве аргументов в опции –process.
Действие, на которое мы хотим проверить процесс, указывается в качестве аргумента в опции –action-id.
Вот пример. Предположим, я хочу проверить, имеет ли интерактивная оболочка, из которой я работаю, право выключить систему (например, выполнив команду “systemctl halt”):
Переменная $$ расширяется до PID текущей оболочки, а опция -u, которую мы использовали в команде, позволяет аутентифицировать пользователя через агента Polkit.
Как только мы выполняем команду, нам действительно предлагается пройти аутентификацию, поскольку действие по ссылке использует “auth_admin_keep” для всех типов пользователей/сессий:
<action id="org.freedesktop.login1.halt"> <description gettext-domain="systemd">Halt the system</description> <message gettext-domain="systemd">Authentication is required to halt the system.</message> <defaults> <allow_any>auth_admin_keep</allow_any> <allow_inactive>auth_admin_keep</allow_inactive> <allow_active>auth_admin_keep</allow_active> </defaults> <annotate key="org.freedesktop.policykit.imply">org.freedesktop.login1.set-wall-message</annotate> </action>
После успешной аутентификации от имени администратора (мой пользователь входит в группу wheel) утилита pkcheck выдает следующее сообщение:
polkit\56temporary_authorization_id=tmpauthz3 polkit\56retains_authorization_after_challenge=true
Поскольку процесс авторизован, код выхода утилиты равен 0:
$ echo $? 0
Если процесс не авторизован, утилита возвращает 3 в качестве статуса exist.
Более конкретные коды выхода можно найти в manpage.
В приведенном выше примере мы указали только PID процесса, который хотим проверить, однако, чтобы избежать условий гонки (PID могут быть переработаны), рекомендуется использовать формат “pid,start-time,uid”.
Чтобы узнать время начала процесса, например, можно посмотреть на столбец 22 соответствующего файла в псевдофайловой системе /proc.
Чтобы получить значение времени запуска процесса с PID 87325, выполним команду:
или
pkexec
Утилита pkexec позволяет пользователю выполнять программу от имени другого пользователя, обычно от имени root.
По сути, это то же самое, что делает sudo: главное и существенное различие между ними в том, что pkexec работает в контексте инфраструктуры Polkit, со всеми ее преимуществами и сложностями.
Чтобы выполнить команду от имени root с помощью pkexec, мы просто передаем программу в качестве аргумента pkexec.
Вот пример, в котором мы пытаемся обновить Fedora с помощью команды dnf update:
Если мы работаем в GNOME или другой графической среде, которая предоставляет собственную версию агента polkit, нам будет предложено пройти аутентификацию в графической подсказке; если мы выполняем команду с TTY, вместо этого появится текстовая подсказка, поскольку Polkit вернется к агенту pkttyagent:
==== AUTHENTICATING FOR org.freedesktop.policykit.exec ==== Authentication is needed to run `/usr/bin/dnf update' as the super user Authenticating as: doc Password:
🐧 Linux: Разница между /dev/tty, /dev/tty0 и /dev/console
После успешной аутентификации команда должна быть выполнена без проблем.
К сожалению, в последних версиях Polkit, скорее всего, вместо этого вы получите уведомление об ошибке:
polkit-agent-helper-1: error response to PolicyKit daemon: GDBus.Error:org.freedesktop.PolicyKit1.Error.Failed: No session for cookie ==== AUTHENTICATION FAILED ==== Error executing command as another user: Not authorized This incident has been reported.
Это связано с известной ошибкой. Возможное решение заключается в явном запуске текстового агента:
По умолчанию, когда используется pkaction, он ссылается на действие org.freedesktop.policykit.exec, определенное в файле /usr/share/polkit-1/actions/org.freedesktop.policykit.policy.
Если мы хотим, чтобы pkexec ссылался на пользовательское действие, мы используем аннотацию org.freedesktop.policykit.exec.path для этого действия и задаем путь программы, которую мы хотим выполнить, в качестве содержимого тега “annotate”.
Именно так, по крайней мере на Fedora, поступает По умолчанию, когда используется pkaction, он ссылается на действие org.freedesktop.policykit.exec, определенное в файле /usr/share/polkit-1/actions/org.freedesktop.policykit.policy.
Если мы хотим, чтобы pkexec ссылался на пользовательское действие, мы используем аннотацию org.freedesktop.policykit.exec.path для этого действия и задаем путь программы, которую мы хотим выполнить, в качестве содержимого тега “annotate”.
Именно так, по крайней мере на Fedora, поступает Gparted в файле /usr/share/polkit-1/actions/org.gnome.gparted.policy:в файле /usr/share/polkit-1/actions/org.gnome.gparted.policy:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE policyconfig PUBLIC "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN" "http://www.freedesktop.org/standards/PolicyKit/1/policyconfig.dtd"> <policyconfig> <vendor>The GParted Project</vendor> <vendor_url>https://gparted.org</vendor_url> <icon_name>gparted</icon_name> <action id="org.gnome.gparted"> <description>Run GParted as root</description> <message>Authentication is required to run the GParted Partition Editor as root</message> <defaults> <allow_any>auth_admin</allow_any> <allow_inactive>auth_admin</allow_inactive> <allow_active>auth_admin</allow_active> </defaults> <annotate key="org.freedesktop.policykit.exec.path">/usr/bin/gparted</annotate> <annotate key="org.freedesktop.policykit.exec.allow_gui">true</annotate> </action> </policyconfig>
Обратите внимание на другую аннотацию, используемую в действии: org.freedesktop.policykit.exec.allow_gui.
Это необходимо, потому что при использовании pkexec он отбрасывает множество переменных окружения, чтобы поддерживать минимальное знание окружения в целях безопасности.
Это делает невозможным запуск X11-приложений, так как переменные DISPLAY и XAUTHORITY отбрасываются.
Использование аннотации отключает это поведение.
Заключение
В этом уроке мы рассказали о Polkit и D-Bus и увидели, как эти две технологии связаны между собой.
Polkit – это фреймворк авторизации, который предоставляет API, позволяющий непривилегированным субъектам получать доступ к привилегированным сервисам.
В этом уроке мы рассмотрели, как работает Polkit, как определяются действия и правила Polkit, а также как использовать утилиты pkaction, pkcheck, pkexec.
см. также:
- 🐉 Как сделать постоянный Live USB с Kali Linux
- Альтернативы PuTTY
- 🐧 Форматирование SD-карты, USB-накопителя, флэш-накопителя на Linux с помощью parted
- 🐧 Как предотвратить случайное удаление записей Crontab на Linux
- 🐧 SCP vs RSYNC – что из них использовать в продакшене?
- 🔐 Как проверить конфигурацию клиента SSH