Временное повышение прав в PostgreSQL: безопасные методы для мониторинга и управления процессами

    Администраторы баз данных часто сталкиваются с задачей предоставления ограниченных привилегий обычным пользователям - например, права на просмотр всех активных соединений в pg_stat_activity и возможность завершать (kill) чужие процессы. При этом выдавать полные права суперпользователя (SUPERUSER) небезопасно. В PostgreSQL существует несколько механизмов для временного повышения прав, аналогичных indirect ролям в Sybase.

    Как временно повысить привилегии без SUPERUSER

    PostgreSQL не имеет встроенной конструкции indirect role, как в Sybase, но предлагает гибкие инструменты: предопределённые роли, атрибут SECURITY DEFINER и контекстные функции. Рассмотрим их по порядку.

    Предопределённая роль pg_read_all_stats

    Роль pg_read_all_stats предоставляет доступ к статистическим представлениям, включая pg_stat_activity. Выдача этой роли обычному пользователю безопасна, если вы доверяете ему чтение данных о производительности. Однако она не даёт права завершать процессы. Для киллинга потребуется дополнительный механизм.

    Функции с SECURITY DEFINER для временного повышения прав

    Атрибут SECURITY DEFINER позволяет функции выполняться с правами её владельца (обычно суперпользователя). Вопреки распространённому заблуждению, это работает не только для операций чтения - внутри такой функции можно выполнять любые действия, включая pg_terminate_backend(). Главное - ограничить входные параметры и добавить проверки.

    Пример безопасной функции для киллинга процесса:

    CREATE OR REPLACE FUNCTION public.kill_user_process(pid integer)
    RETURNS boolean
    LANGUAGE plpgsql
    SECURITY DEFINER
    AS $$
    BEGIN
        IF EXISTS (SELECT 1 FROM pg_stat_activity WHERE pid = $1) THEN
            PERFORM pg_terminate_backend($1);
            RETURN true;
        ELSE
            RETURN false;
        END IF;
    END;
    $$;
    REVOKE EXECUTE ON FUNCTION public.kill_user_process FROM PUBLIC;
    GRANT EXECUTE ON FUNCTION public.kill_user_process TO username;

    Владельцем функции должен быть суперпользователь. После создания права на выполнение выдаются только конкретному пользователю. Такой подход безопасен, так как функция не позволяет выполнять произвольный SQL.

    Комбинация pg_read_all_stats и функции-обёртки

    Для полного решения задачи (просмотр всех процессов + киллинг) рекомендуется:

    • Выдать пользователю роль pg_read_all_stats - это даст доступ к pg_stat_activity.
    • Создать функцию с SECURITY DEFINER для pg_terminate_backend.
    • Назначить права на выполнение функции только нужному пользователю.

    Безопасность и рекомендации

    Временное повышение прав через SECURITY DEFINER считается безопасным, если:

    • Функция не принимает динамический SQL (риск SQL-инъекции).
    • Входные параметры строго проверяются.
    • Функция выполняет только конкретную операцию (например, завершение процесса по PID).

    Не рекомендуется выдавать роль pg_signal_backend напрямую обычным пользователям - она даёт право завершать любые процессы без дополнительных проверок. Используйте функцию-обёртку с логированием или ограничениями.

    Альтернативные подходы

    Если требуется более гибкое временное повышение прав, рассмотрите:

    • Использование расширения pg_background для выполнения задач с повышенными привилегиями.
    • Создание процедуры с SECURITY DEFINER (в PostgreSQL 11+ процедуры также поддерживают этот атрибут).
    • Применение контекстных переменных через SET SESSION внутри функции - это позволяет временно изменять параметры сессии.

    Таким образом, в PostgreSQL нет встроенного механизма indirect role, но комбинация предопределённых ролей и функций с SECURITY DEFINER полностью решает задачу временного повышения прав для мониторинга и управления процессами.

    Часто задаваемые вопросы