🐧 Введение в Polkit: Навигация по фреймворкам авторизации в Linux |

🐧 Введение в Polkit: Навигация по фреймворкам авторизации в Linux

Статьи

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.

Когда утилита вызывается без каких-либо аргументов или опций, она отображает все зарегистрированные действия:

pkaction

Вот выдержка из результатов выполнения команды на стандартной установке 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:

pkaction --verbose --action-id org.freedesktop.login1.halt

Вот вывод, который мы получим:

pkcheck

Утилита pkcheck используется для проверки того, авторизован ли процесс на выполнение определенного действия, предоставляемого сервисом в системе dbus.

По сути, эта утилита представляет собой способ командной строки для вызова метода CheckAuathorization, предоставляемого интерфейсом polkit D-Bus.

Процесс может быть идентифицирован по имени системной шины или путем передачи таких деталей, как его PID, время запуска и uid.

Для использования последней стратегии мы передаем эти данные в качестве аргументов в опции –process.

Действие, на которое мы хотим проверить процесс, указывается в качестве аргумента в опции –action-id.

Вот пример. Предположим, я хочу проверить, имеет ли интерактивная оболочка, из которой я работаю, право выключить систему (например, выполнив команду “systemctl halt”):

pkcheck -u --process $$ --action-id org.freedesktop.login1.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, выполним команду:

cat /proc/87325/stat | cut -d ' ' -f 22

или

awk -F ' ' '{print $22}' /proc/87325/stat

pkexec

Утилита pkexec позволяет пользователю выполнять программу от имени другого пользователя, обычно от имени root.

По сути, это то же самое, что делает sudo: главное и существенное различие между ними в том, что pkexec работает в контексте инфраструктуры Polkit, со всеми ее преимуществами и сложностями.

Чтобы выполнить команду от имени root с помощью pkexec, мы просто передаем программу в качестве аргумента pkexec.

Вот пример, в котором мы пытаемся обновить Fedora с помощью команды dnf update:

pkexec 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.

Это связано с известной ошибкой. Возможное решение заключается в явном запуске текстового агента:

pkttyagent -p $(echo $$) | pkexec dnf update

По умолчанию, когда используется 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.

см. также:

Пожалуйста, не спамьте и никого не оскорбляйте. Это поле для комментариев, а не спамбокс. Рекламные ссылки не индексируются!
Добавить комментарий