GrantForge

    Плагины

    Прокси-агент MySQL

    Разверните сетевой прокси MySQL, настройте TLS и синхронизацию политик и проверьте права на столбцы, маскирование, фильтры строк и ошибки отказа.

    Агент MySQL — это независимый сетевой прокси: клиенты подключаются к нему вместо сервера, а он проверяет поддерживаемые SQL-операторы по подписанным политикам сервиса данных mysql до их передачи MySQL. Установка внутрь сервера MySQL не требуется. Дистрибутив содержит исполняемый JAR agents/mysql/grantforge-agent-mysql-<version>.jar, для которого нужна Java 17 или новее.

    Интеграционные тесты Testcontainers в репозитории рассчитаны на mysql:8.0 и mysql:8.4 с клиентами MariaDB Connector/J и MySQL Connector/J. Это не подтверждает совместимость с другими версиями серверов или всеми возможностями протокола MySQL. Требования к версии и подключению сервисного плагина приведены в разделе MySQL.

    Принцип работы

    • Вход передаётся серверу. Приветствие сервера поступает клиенту, а ответы клиента — серверу, поэтому пароль проверяет сам MySQL (caching_sha2_password и mysql_native_password); прокси узнаёт имя принятого пользователя. В политиках указывается это имя без части с хостом.
    • Проверяются ресурсы SQL. Прокси разбирает COM_QUERY и подготовленные операторы на стороне сервера и проверяет типы доступа, необходимые для их баз данных, таблиц и столбцов. Отклонённый оператор не попадает в MySQL: прокси формирует ошибку с совместимым с MySQL кодом, например 1142 или 1143.
    • Чтение маскируется и фильтруется. Если для пользователя задано маскирование столбцов или фильтр строк читаемой таблицы, прокси заменяет её производной таблицей с тем же именем. Она показывает замаскированные значения и только строки, прошедшие фильтр, поэтому соединения, условия и функции работают с доступным пользователю представлением данных.
    • События авторизации ресурсов отправляются в GrantForge вместе с пользователем, адресом клиента, ресурсом, типом доступа, решением и SQL-оператором. Область аудита описана ниже.
    • Результаты выполнения MySQL передаются клиенту; прокси не меняет исходные значения, сохранённые в базе данных.

    Развёртывание

    1. Добавьте сервис данных mysql и настройте его политики. Откройте Права доступа к данным → Агенты, выберите сервис и выпустите токен агента. Он показывается только один раз; сохраните его в файл, доступный для чтения только учётной записи прокси.

    2. Создайте пользователя метаданных для прокси. Он читает столбцы таблиц и хранимые функции из information_schema, не читая сами данные: REFERENCES делает видимыми все столбцы, а SHOW_ROUTINE — все хранимые функции. Выдайте права непосредственно пользователю, не через роль; без SHOW_ROUTINE прокси не запустится.

      CREATE USER 'grantforge_meta'@'proxy-host' IDENTIFIED BY '…';
      GRANT REFERENCES, SHOW_ROUTINE ON *.* TO 'grantforge_meta'@'proxy-host';
    3. Создайте файл настроек, заменив адреса, пути и имена в примере:

      grantforge.server.url=https://grantforge.example.com
      grantforge.token.file=/etc/grantforge/mysql-proxy.token
      grantforge.instance=mysql-proxy-1
      grantforge.cache.dir=/var/lib/grantforge/mysql-proxy
      grantforge.proxy.host=0.0.0.0
      grantforge.proxy.port=3307
      grantforge.proxy.tls.cert=/etc/grantforge/mysql-proxy.crt
      grantforge.proxy.tls.key=/etc/grantforge/mysql-proxy.key
      grantforge.proxy.tls.required=true
      grantforge.mysql.host=mysql.internal
      grantforge.mysql.port=3306
      grantforge.mysql.tls=verify-identity
      grantforge.mysql.tls.ca=/etc/grantforge/mysql-ca.pem
      grantforge.mysql.metadata.user=grantforge_meta
      grantforge.mysql.metadata.password.file=/etc/grantforge/mysql-meta.password

      Этот пример включает TLS между клиентами и прокси, а также между прокси и MySQL. mysql-proxy.crt должен соответствовать имени хоста прокси, используемому клиентами; сертификат MySQL должен соответствовать mysql.internal. Пути относятся к машине прокси, а каталог кеша должен быть доступен для записи. Файлы паролей читаются как UTF-8 с удалением пробелов в начале и конце, поэтому пароли, которым нужны такие пробелы, нельзя хранить этим способом.

    4. Запустите прокси, например как службу systemd:

      java -jar agents/mysql/grantforge-agent-mysql-<version>.jar /etc/grantforge/mysql-proxy.properties

      Замените <version> версией дистрибутива. Параметры java -Dgrantforge.…=… -jar … имеют приоритет над файлом. При SIGTERM прокси корректно останавливается и отправляет или сохраняет ожидающие события на диск.

    5. Направьте клиентов на адрес и порт прокси. MySQL теперь видит адрес прокси, поэтому часть хоста в учётных записях должна разрешать его.

    6. Закройте обходной путь: клиенты, которые могут подключаться напрямую к MySQL, не проверяются. Доступ к порту сервера должен быть только у прокси и администраторов.

    Параметр Назначение
    grantforge.server.url, grantforge.token.file, grantforge.instance, grantforge.cache.dir Обязательные: сервер GrantForge, файл токена агента, имя этого прокси и доступный для записи каталог подписанного снимка и отложенных событий
    grantforge.signing.key.file Необязательный файл закреплённого ключа подписи снимков; скопируйте открытый ключ Ed25519 в формате X.509 с кодированием Base64 со страницы агентов. Без этой настройки ключ загружается с сервера при первом обращении
    grantforge.proxy.host, grantforge.proxy.port Адрес прослушивания; по умолчанию все адреса и порт 3307. Диапазон портов 0..65535; 0 назначает порт автоматически
    grantforge.proxy.tls.cert, grantforge.proxy.tls.key Сертификат и закрытый ключ PEM; для TLS клиентам необходимо задать оба
    grantforge.proxy.tls.required По умолчанию false; true отклоняет клиентов без TLS (ошибка 3159) и требует сертификат с закрытым ключом
    grantforge.mysql.host, grantforge.mysql.port Хост MySQL обязателен; порт по умолчанию 3306, диапазон 1..65535
    grantforge.mysql.tls TLS к MySQL: disabled (по умолчанию), required (шифрование без проверки), verify-ca или verify-identity
    grantforge.mysql.tls.ca CA в формате PEM для проверки MySQL; если не задан, используются сертификаты, которым доверяет Java
    grantforge.mysql.metadata.user, grantforge.mysql.metadata.password.file Пользователь метаданных обязателен; файл пароля необязателен, без него пароль драйверу не передаётся
    grantforge.mysql.metadata.cache.seconds Срок хранения кеша столбцов и хранимых функций: по умолчанию 30 секунд, диапазон 0..86400; 0 отключает повторное использование кеша
    grantforge.mysql.connect.timeout.ms Тайм-аут соединения с MySQL: по умолчанию 10000 мс, диапазон 1..600000; тайм-аут чтения метаданных фиксирован и равен 30000 мс
    grantforge.proxy.check.threads Потоки проверки операторов: по умолчанию 8, диапазон 1..256
    grantforge.connect.timeout.ms, grantforge.read.timeout.ms Тайм-ауты соединения и чтения GrantForge: по умолчанию 5000 / 8000 мс, диапазон 1..2147483647
    grantforge.refresh.interval.ms Начальный или резервный интервал обновления при недоступности сервера: по умолчанию 30000 мс, минимум 1000; обычные heartbeat используют интервал, возвращённый сервером
    grantforge.audit.batch.size, grantforge.audit.queue.capacity По умолчанию пакет 500, очередь 10000 событий; диапазон пакета 1..1000, очередь не меньше пакета и не больше 1000000
    grantforge.audit.flush.interval.ms Интервал отправки аудита: по умолчанию 5000 мс, диапазон 1..2147483647
    grantforge.audit.spool.limit.bytes Предел дискового буфера аудита: по умолчанию 67108864 (64 MiB), минимум 0

    TLS с двух сторон независим. Если TLS используется только с одной стороны, а MySQL запрашивает полный пароль (caching_sha2_password при отсутствии записи в кеше), прокси передаёт его между сторонами: на запрос открытого ключа сервера от незашифрованного клиента он отвечает собственным RSA-ключом, а пароль TLS-клиента шифрует ключом MySQL для незашифрованного сервера. При подключении через прокси не настраивайте у клиента файл открытого ключа MySQL.

    Права, необходимые операторам

    Оператор Доступ
    SELECT, подзапросы, WITH, EXPLAIN, SET @x = (SELECT …) select на каждый используемый столбец; чтение таблицы без чтения столбцов, например COUNT(*) или EXISTS, требует select на всю таблицу
    INSERT, LOAD DATA insert на записываемые столбцы (на все, если список не указан); ON DUPLICATE KEY UPDATE дополнительно требует update
    REPLACE insert на столбцы и delete на таблицу
    UPDATE update на изменяемые столбцы и select на читаемые
    DELETE delete на таблицу и select на читаемые столбцы
    CREATE TABLE, CREATE VIEW / DROP TABLE, DROP VIEW, TRUNCATE / ALTER TABLE, ALTER VIEW, OPTIMIZE create / drop / alter на таблицу или представление
    RENAME TABLE alter и drop на старое имя, create и insert на новое
    CREATE INDEX, DROP INDEX index на таблицу
    CREATE DATABASE, DROP DATABASE create, drop на базу данных
    LOCK TABLES, ANALYZE, CHECK, CHECKSUM TABLE select на таблицу

    Операторы без обращения к данным передаются штатной системе прав MySQL: транзакции, SET, USE, SHOW, DESCRIBE, KILL, а также управление учётными записями, например GRANT и CREATE USER. information_schema и performance_schema требуют политик так же, как другие базы данных.

    Прокси отклоняет то, что не может проверить полностью: исполняемые комментарии (/*! … */), хранимые функции и CALL, CREATE PROCEDURE, FUNCTION, TRIGGER и EVENT, SQL-операторы PREPARE/EXECUTE, HANDLER, команды репликации и клонирования, USE или SET NAMES вместе с другими операторами в одном пакете, а также операторы, которые не удаётся разобрать.

    Маскирование, фильтры строк и ограничения

    • Маски и фильтры применяются при чтении таблицы, в том числе в подзапросах, соединениях, INSERT … SELECT и CREATE TABLE … SELECT (копия содержит уже замаскированные значения).
    • UPDATE или DELETE для одной таблицы меняет только строки, видимые через фильтр. Многотабличные UPDATE или DELETE для таблицы с фильтром отклоняются, как и запись, использующая маскируемый столбец изменяемой таблицы, поскольку это могло бы скопировать или раскрыть скрытые значения.
    • Нельзя создать или изменить представление над таблицей с маскированием или фильтром строк: впоследствии MySQL выполняет представление без участия прокси.
    • Подготовленные операторы повторно используют проверку и переписывание, пока версия политик не меняется. При смене версии выполняется повторная проверка: если доступ по-прежнему разрешён и переписанный текст не изменился, выполнение продолжается; иначе ошибка 1615 требует подготовить оператор заново.
    • Столбец без имени таблицы учитывается для каждой таблицы в его области видимости, где есть одноимённый столбец. Указывайте таблицу, чтобы ограниченный столбец с тем же именем не вызвал отказ.
    • Столбцы, читаемые через *, берутся из видимого пользователю метаданных information_schema и кешируются на grantforge.mysql.metadata.cache.seconds. Успешный DDL, отправленный через прокси обычной SQL-командой, делает кеш недействительным, поэтому следующий поиск читает данные заново. Внешний или подготовленный DDL не гарантирует сброс кеша при выполнении; дождитесь истечения срока кеша или перезапустите прокси.

    Область применения

    Прокси проверяет ресурсы, которые может разобрать в SQL клиента. Он не разворачивает рекурсивно существующие представления, триггеры и другие операции, выполняемые внутри сервера. Для защиты базовых таблиц также ограничьте штатные права MySQL и использование существующих представлений и триггеров. Не выдавайте бизнес-пользователям права администратора в расчёте на перехват административных операторов прокси.

    Фильтр строк не является общим ограничением записи: INSERT, REPLACE и LOAD DATA проверяют права записи, но не требуют автоматически, чтобы новые строки удовлетворяли выражению фильтра. В ветку обновления существующей строки INSERT … ON DUPLICATE KEY UPDATE также не добавляется условие фильтра. Сжатие протокола, ZSTD, атрибуты запросов и необязательные метаданные результата отключаются при согласовании соединения.

    Политики и сбои

    • Без пригодного снимка или с токеном, привязанным к сервису не типа mysql, все операторы, обращающиеся к данным, отклоняются.
    • При временной недоступности GrantForge или неверной подписи нового снимка прокси сохраняет уже применённый снимок. Первый запуск без пригодного снимка отклоняет доступ к ресурсам.
    • Отключение сервиса пропускает авторизацию ресурсов GrantForge, маскирование и фильтрацию строк; разбор SQL и ограничения протокола сохраняются. Отключение сервиса не блокирует доступ к данным.
    • После проверок прокси по-прежнему действуют права MySQL; прокси может только сузить их.
    • Прокси отслеживает COM_CHANGE_USER, но отклоняет его, если TLS на стороне клиента и сервера различается; вместо этого подключитесь заново под другим пользователем.

    Пример проверки

    Попросите администратора базы данных создать следующие данные и учётную запись в отдельной тестовой базе. Замените proxy-host адресом источника прокси, который фактически видит MySQL:

    CREATE DATABASE grantforge_demo;
    CREATE TABLE grantforge_demo.orders (id INT PRIMARY KEY, region VARCHAR(8), card VARCHAR(32));
    INSERT INTO grantforge_demo.orders VALUES (1, 'EU', '4111111111111111'), (2, 'US', '5555555555554444');
    CREATE USER 'alice'@'proxy-host' IDENTIFIED BY 'replace-with-a-password';
    GRANT SELECT, UPDATE ON grantforge_demo.* TO 'alice'@'proxy-host';

    Создайте три политики GrantForge для alice: разрешите select для database=grantforge_demo, table=orders, column=*; маскируйте card типом mask_show_last_4; задайте фильтр таблицы region = 'EU'. Сервис и все три политики должны быть включены. Дождитесь, пока раздел Права доступа к данным → Агенты покажет применение последней версии политик.

    Подключитесь к прокси командным клиентом MySQL. -p запрашивает пароль; файл CA должен обеспечивать доверие сертификату прокси:

    mysql --host=mysql-proxy.example.com --port=3307 --user=alice -p \
      --ssl-mode=VERIFY_IDENTITY --ssl-ca=/path/to/proxy-ca.pem grantforge_demo
    SELECT id, region, card FROM orders ORDER BY id;
    -- Только одна строка: 1 | EU | xxxxxxxxxxxx1111
     
    UPDATE orders SET region = 'US' WHERE id = 1;
    -- 1143 / 42000: GrantForge не разрешает update

    В этом примере штатные права MySQL уже разрешают UPDATE, поэтому отказ подтверждает применение политики прокси. Затем измените фильтр на region = 'US', дождитесь применения новой версии и повторите запрос. Должна появиться только строка 2 с картой xxxxxxxxxxxx4444.

    Устранение неполадок и аудит

    Код ошибки / SQLSTATE Значение и проверки
    1044 / 42000, 1142 / 42000, 1143 / 42000 Доступ к базе данных, таблице или столбцу запрещён. Если сообщение содержит by GrantForge, проверьте пользователя политики, ресурсы, тип доступа и версию снимка; при других отказах также проверьте штатные права MySQL
    1046 / 3D000 База данных не выбрана; используйте USE, базу по умолчанию в соединении или полное имя таблицы
    1227 / 42000 Операция запрещена или не может быть безопасно проверена; по сообщению проверьте ограничения операторов и права на метаданные
    1064 / 42000 Не удаётся разобрать SQL
    1615 / HY000 После изменения политик подготовьте оператор заново
    3159 / HY000 Прокси требует TLS, но клиент подключился без него
    1043 / 08S01 Ошибка согласования протокола или TLS с сервером; проверьте режим TLS, сертификаты, имя хоста и возможности сервера
    2003 / HY000 Прокси не может подключиться к MySQL; проверьте адрес, сеть и состояние сервера

    В разделе Права доступа к данным → Аудит доступа найдите разрешения и отказы для alice и соответствующих ресурсов. Один SQL-оператор может создавать несколько событий авторизации ресурсов. Они записываются до выполнения сервером, поэтому ALLOWED не означает успешное выполнение в MySQL. Ошибки разбора, операторы без доступа к ресурсам и отключённые сервисы могут не создавать таких событий; повторные выполнения подготовленного оператора при той же версии политик не повторяют события авторизации. Это аудит авторизации ресурсов, а не полный журнал выполнения SQL.

    Связанные руководства

    Редактировать эту страницу на GitHub