Аудит экземпляра Grafana

Аудит позволяет отслеживать важные изменения в вашем экземпляре Grafana. В зависимости от вашего развёртывания вы можете отправлять журналы аудита в файл, на совместимую с Loki конечную точку или в стандартный логгер Grafana.

Note

Доступно в Grafana Enterprise и Grafana Cloud.

Журнал аудита создаётся только для запросов к API или действий в интерфейсе, которые вызывают запрос к API.

  • Grafana Enterprise поддерживает все три экспортёра: file, Loki и console.
  • Grafana Cloud использует экспортёр Loki. Чтобы включить журналы аудита для вашего экземпляра Grafana Cloud, создайте обращение в службу поддержки. Применяются стандартные тарифы на приём и хранение.

Как устроены журналы аудита

Журналы аудита — это объекты JSON, представляющие действия пользователей, например:

  • Изменения ресурсов, таких как дашборды и источники данных.
  • Неудачная попытка пользователя войти в систему.

Формат журнала аудита

Журналы аудита содержат следующие поля. Поля, помеченные *, присутствуют всегда, остальные зависят от типа записанного действия.

Имя поля Тип Описание
timestamp* string Дата и время выполнения запроса в формате всемирного координированного времени (UTC) согласно RFC3339.
user* object Информация о пользователе, выполнившем запрос. Если isAnonymous=false, содержимое есть в одном из полей UserID или ApiKeyID.
user.userId number ID пользователя Grafana, выполнившего запрос.
user.orgId* number Текущая организация пользователя, выполнившего запрос.
user.orgRole string Текущая роль пользователя, выполнившего запрос.
user.name string Имя пользователя Grafana, выполнившего запрос.
user.authTokenId number ID токена аутентификации пользователя.
user.apiKeyId number ID ключа API Grafana, использованного для выполнения запроса.
user.isAnonymous* boolean true, если запрос выполнил анонимный пользователь. В противном случае false.
action* string Действие запроса. Например, create, update или manage-permissions.
request* object Информация об HTTP-запросе.
request.params object Параметры пути запроса.
request.query object Параметры строки запроса.
request.body string Тело запроса. Заполняется значением <non-marshalable format>, если это не корректный JSON.
result* object Информация об HTTP-ответе.
result.statusType string success, если действие запроса выполнено успешно. В противном случае failure.
result.statusCode number HTTP-статус запроса.
result.failureMessage string Сообщение об ошибке HTTP.
result.body string Тело ответа. Заполняется значением <non-marshalable format>, если это не корректный JSON.
resources array Информация о ресурсах, которых коснулось действие запроса. Это поле может быть null для действий, не связанных с ресурсами, таких как login или logout.
resources[x].id number ID ресурса, если доступен.
resources[x].type* string Тип записанного ресурса: alert, alert-notification, annotation, api-key, auth-token, dashboard, datasource, folder, org, panel, playlist, report, team, user или version.
resources[x].uid string UID ресурса, если доступен.
resources[x].name string Имя ресурса, если доступно. Сейчас Grafana заполняет это поле для ресурсов user.
requestUri* string URI запроса.
ipAddress* string IP-адрес, с которого выполнен запрос.
userAgent* string Агент, с помощью которого выполнен запрос.
grafanaVersion* string Текущая версия Grafana на момент создания этой записи журнала.
additionalData object Дополнительная информация, которая может быть предоставлена о запросе.

Поле additionalData может содержать следующую информацию:

Имя поля Действие Описание
loginUsername login Логин, использованный в форме аутентификации Grafana.
extUserInfo login Информация о пользователе, предоставленная внешней системой, использованной для входа.
authTokenCount login Количество активных токенов аутентификации у вошедшего пользователя.
terminationReason logout Причина выхода пользователя, например ручной выход или истечение срока действия токена.
billing_role billing-information Роль для выставления счетов, связанная с отправляемой информацией о выставлении счетов.

Определение записанных действий

Журналы аудита включают записи о следующих категориях действий. Каждое действие различается по полям action и resources[...].type в записи JSON.

Например, создание ключа API порождает такой журнал аудита:

JSON
{
  "action": "create",
  "resources": [
    {
      "id": 1,
      "type": "api-key"
    }
  ],
  "timestamp": "2021-11-12T22:12:36.144795692Z",
  "user": {
    "userId": 1,
    "orgId": 1,
    "orgRole": "Admin",
    "username": "admin",
    "isAnonymous": false,
    "authTokenId": 1
  },
  "request": {
    "body": "{\"name\":\"example\",\"role\":\"Viewer\",\"secondsToLive\":null}"
  },
  "result": {
    "statusType": "success",
    "statusCode": 200,
    "responseBody": "{\"id\":1,\"name\":\"example\"}"
  },
  "resources": [
    {
      "id": 1,
      "type": "api-key"
    }
  ],
  "requestUri": "/api/auth/keys",
  "ipAddress": "127.0.0.1:54652",
  "userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:94.0) Gecko/20100101 Firefox/94.0",
  "grafanaVersion": "8.3.0-pre"
}

Некоторые действия можно различить только по их полям requestUri. Для таких действий приводится соответствующий шаблон поля requestUri.

Почти все записанные действия соответствуют запросам к API или действиям в интерфейсе, которые вызывают запрос к API. Например, действие {"action": "email", "resources": [{"type": "report"}]} соответствует инициированному пользователем предпросмотру отчёта по электронной почте, а не отправке по расписанию.

Сессии

Действие Различающие поля
Вход в систему {"action": "login-AUTH-MODULE"} *
Выход из системы ** {"action": "logout"}
Принудительный выход пользователя {"action": "logout-user"}
Удаление токена аутентификации пользователя {"action": "revoke-auth-token", "resources": [{"type": "auth-token"}, {"type": "user"}]}
Создание ключа API {"action": "create", "resources": [{"type": "api-key"}]}
Удаление ключа API {"action": "delete", "resources": [{"type": "api-key"}]}

* Где AUTH-MODULE — имя модуля аутентификации: grafana, saml, ldap и т. д.
** Включает ручной выход, истечение/отзыв токена и единый выход SAML.

Сервисные учётные записи

Действие Различающие поля
Создание сервисной учётной записи {"action": "create", "resources": [{"type": "service-account"}]}
Обновление сервисной учётной записи {"action": "update", "resources": [{"type": "service-account"}]}
Удаление сервисной учётной записи {"action": "delete", "resources": [{"type": "service-account"}]}
Создание токена сервисной учётной записи {"action": "create", "resources": [{"type": "service-account"}, {"type": "service-account-token"}]}
Удаление токена сервисной учётной записи {"action": "delete", "resources": [{"type": "service-account"}, {"type": "service-account-token"}]}
Скрытие ключей API {"action": "hide-api-keys"}
Миграция ключей API {"action": "migrate-api-keys"}
Миграция ключа API {"action": "migrate-api-keys"}, "resources": [{"type": "api-key"}]}

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

Действие Различающие поля
Создание роли {"action": "create", "resources": [{"type": "role"}]}
Обновление роли {"action": "update", "resources": [{"type": "role"}]}
Удаление роли {"action": "delete", "resources": [{"type": "role"}]}
Назначение встроенной роли {"action": "assign-builtin-role", "resources": [{"type": "role"}, {"type": "builtin-role"}]}
Снятие встроенной роли {"action": "remove-builtin-role", "resources": [{"type": "role"}, {"type": "builtin-role"}]}
Предоставление роли команды {"action": "grant-team-role", "resources": [{"type": "team"}]}
Установка ролей команды {"action": "set-team-roles", "resources": [{"type": "team"}]}
Отзыв роли команды {"action": "revoke-team-role", "resources": [{"type": "role"}, {"type": "team"}]}
Предоставление роли пользователя {"action": "grant-user-role", "resources": [{"type": "role"}, {"type": "user"}]}
Установка ролей пользователя {"action": "set-user-roles", "resources": [{"type": "user"}]}
Отзыв роли пользователя {"action": "revoke-user-role", "resources": [{"type": "role"}, {"type": "user"}]}
Установка прав пользователя на папку {"action": "set-user-permissions-on-folder", "resources": [{"type": "folder"}, {"type": "user"}]}
Установка прав команды на папку {"action": "set-team-permissions-on-folder", "resources": [{"type": "folder"}, {"type": "team"}]}
Установка прав базовой роли на папку {"action": "set-basic-role-permissions-on-folder", "resources": [{"type": "folder"}, {"type": "builtin-role"}]}
Установка прав пользователя на дашборд {"action": "set-user-permissions-on-dashboards", "resources": [{"type": "dashboard"}, {"type": "user"}]}
Установка прав команды на дашборд {"action": "set-team-permissions-on-dashboards", "resources": [{"type": "dashboard"}, {"type": "team"}]}
Установка прав базовой роли на дашборд {"action": "set-basic-role-permissions-on-dashboards", "resources": [{"type": "dashboard"}, {"type": "builtin-role"}]}
Установка прав пользователя на команду {"action": "set-user-permissions-on-teams", "resources": [{"type": "teams"}, {"type": "user"}]}
Установка прав пользователя на сервисную учётную запись {"action": "set-user-permissions-on-service-accounts", "resources": [{"type": "service-account"}, {"type": "user"}]}
Установка прав пользователя на источник данных {"action": "set-user-permissions-on-data-sources", "resources": [{"type": "datasource"}, {"type": "user"}]}
Установка прав команды на источник данных {"action": "set-team-permissions-on-data-sources", "resources": [{"type": "datasource"}, {"type": "team"}]}
Установка прав базовой роли на источник данных {"action": "set-basic-role-permissions-on-data-sources", "resources": [{"type": "datasource"}, {"type": "builtin-role"}]}

Управление пользователями

Действие Различающие поля
Создание пользователя {"action": "create", "resources": [{"type": "user"}]}
Обновление пользователя {"action": "update", "resources": [{"type": "user"}]}
Удаление пользователя {"action": "delete", "resources": [{"type": "user"}]}
Отключение пользователя {"action": "disable", "resources": [{"type": "user"}]}
Включение пользователя {"action": "enable", "resources": [{"type": "user"}]}
Обновление пароля {"action": "update-password", "resources": [{"type": "user"}]}
Отправка письма для сброса пароля {"action": "send-reset-email"}
Сброс пароля {"action": "reset-password"}
Обновление прав {"action": "update-permissions", "resources": [{"type": "user"}]}
Отправка письма для регистрации {"action": "signup-email"}
Переход по ссылке регистрации {"action": "signup"}
Перезагрузка конфигурации LDAP {"action": "ldap-reload"}
Получение пользователя в LDAP {"action": "ldap-search"}
Синхронизация пользователя с LDAP {"action": "ldap-sync", "resources": [{"type": "user"}]

Управление командами и организациями

Действие Различающие поля
Добавление команды {"action": "create", "requestUri": "/api/teams"}
Обновление команды {"action": "update", "requestUri": "/api/teams/TEAM-ID"}*
Удаление команды {"action": "delete", "requestUri": "/api/teams/TEAM-ID"}*
Добавление внешней группы для команды {"action": "create", "requestUri": "/api/teams/TEAM-ID/groups"}*
Удаление внешней группы для команды {"action": "delete", "requestUri": "/api/teams/TEAM-ID/groups/GROUP-ID"}*
Добавление пользователя в команду {"action": "create", "resources": [{"type": "user"}, {"type": "team"}]}
Обновление прав участника команды {"action": "update", "resources": [{"type": "user"}, {"type": "team"}]}
Удаление пользователя из команды {"action": "delete", "resources": [{"type": "user"}, {"type": "team"}]}
Создание организации {"action": "create", "resources": [{"type": "org"}]}
Обновление организации {"action": "update", "resources": [{"type": "org"}]}
Удаление организации {"action": "delete", "resources": [{"type": "org"}]}
Добавление пользователя в организацию {"action": "create", "resources": [{"type": "org"}, {"type": "user"}]}
Изменение роли пользователя в организации {"action": "update", "resources": [{"type": "user"}, {"type": "org"}]}
Удаление пользователя из организации {"action": "delete", "resources": [{"type": "user"}, {"type": "org"}]}
Приглашение внешнего пользователя в организацию {"action": "org-invite", "resources": [{"type": "org"}, {"type": "user"}]}
Отзыв приглашения {"action": "revoke-org-invite", "resources": [{"type": "org"}]}

* Где TEAM-ID — ID затронутой команды, а GROUP-ID (если присутствует) — ID внешней группы.

Управление папками и дашбордами

Действие Различающие поля
Создание папки {"action": "create", "resources": [{"type": "folder"}]}
Обновление папки {"action": "update", "resources": [{"type": "folder"}]}
Обновление прав на папку {"action": "manage-permissions", "resources": [{"type": "folder"}]}
Удаление папки {"action": "delete", "resources": [{"type": "folder"}]}
Создание/обновление дашборда {"action": "create-update", "resources": [{"type": "dashboard"}]}
Импорт дашборда {"action": "create", "resources": [{"type": "dashboard"}]}
Обновление прав на дашборд {"action": "manage-permissions", "resources": [{"type": "dashboard"}]}
Восстановление прежней версии дашборда {"action": "restore", "resources": [{"type": "dashboard"}]}
Удаление дашборда {"action": "delete", "resources": [{"type": "dashboard"}]}

Управление элементами библиотек

Действие Различающие поля
Создание элемента библиотеки {"action": "create", "resources": [{"type": "library-element"}]}
Обновление элемента библиотеки {"action": "update", "resources": [{"type": "library-element"}]}
Удаление элемента библиотеки {"action": "delete", "resources": [{"type": "library-element"}]}

Управление источниками данных

Действие Различающие поля
Создание источника данных {"action": "create", "resources": [{"type": "datasource"}]}
Обновление источника данных {"action": "update", "resources": [{"type": "datasource"}]}
Удаление источника данных {"action": "delete", "resources": [{"type": "datasource"}]}
Включение прав для источника данных {"action": "enable-permissions", "resources": [{"type": "datasource"}]}
Отключение прав для источника данных {"action": "disable-permissions", "resources": [{"type": "datasource"}]}
Предоставление права на источник данных роли, команде или пользователю {"action": "create", "resources": [{"type": "datasource"}, {"type": "dspermission"}]}*
Удаление права на источник данных {"action": "delete", "resources": [{"type": "datasource"}, {"type": "dspermission"}]}
Включение кэширования для источника данных {"action": "enable-cache", "resources": [{"type": "datasource"}]}
Отключение кэширования для источника данных {"action": "disable-cache", "resources": [{"type": "datasource"}]}
Обновление конфигурации кэширования источника данных {"action": "update", "resources": [{"type": "datasource"}]}

* resources также может содержать третий элемент, где "type": имеет значение "user" или "team".

Запросы к источникам данных

Действие Различающие поля
Запрос к источнику данных {"action": "query", "resources": [{"type": "datasource"}]}

Отчётность

Действие Различающие поля
Создание отчёта {"action": "create", "resources": [{"type": "report"}, {"type": "dashboard"}]}
Обновление отчёта {"action": "update", "resources": [{"type": "report"}, {"type": "dashboard"}]}
Удаление отчёта {"action": "delete", "resources": [{"type": "report"}]}
Отправка отчёта по электронной почте {"action": "email", "resources": [{"type": "report"}]}
Обновление настроек отчётности {"action": "change-settings"}

Управление аннотациями, плейлистами и снимками

Действие Различающие поля
Создание аннотации {"action": "create", "resources": [{"type": "annotation"}]}
Создание аннотации Graphite {"action": "create-graphite", "resources": [{"type": "annotation"}]}
Обновление аннотации {"action": "update", "resources": [{"type": "annotation"}]}
Частичное обновление аннотации {"action": "patch", "resources": [{"type": "annotation"}]}
Удаление аннотации {"action": "delete", "resources": [{"type": "annotation"}]}
Удаление всех аннотаций с панели {"action": "mass-delete", "resources": [{"type": "dashboard"}, {"type": "panel"}]}
Создание плейлиста {"action": "create", "resources": [{"type": "playlist"}]}
Обновление плейлиста {"action": "update", "resources": [{"type": "playlist"}]}
Удаление плейлиста {"action": "delete", "resources": [{"type": "playlist"}]}
Создание снимка {"action": "create", "resources": [{"type": "dashboard"}, {"type": "snapshot"}]}
Удаление снимка {"action": "delete", "resources": [{"type": "snapshot"}]}
Удаление снимка по ключу удаления {"action": "delete", "resources": [{"type": "snapshot"}]}

Провижининг

Действие Различающие поля
Перезагрузка провижиненных дашбордов {"action": "provisioning-dashboards"}
Перезагрузка провижиненных источников данных {"action": "provisioning-datasources"}
Перезагрузка провижиненных плагинов {"action": "provisioning-plugins"}
Перезагрузка провижиненных алертов {"action": "provisioning-alerts"}
Перезагрузка провижиненного управления доступом {"action": "provisioning-accesscontrol"}

Управление плагинами

Действие Различающие поля
Установка плагина {"action": "install"}
Удаление плагина {"action": "uninstall"}

Прочее

Действие Различающие поля
Установка токена лицензирования {"action": "create", "requestUri": "/api/licensing/token"}
Сохранение данных для выставления счетов {"action": "billing-information"}

Управление миграцией в облако

Действие Различающие поля
Подключение к облачному экземпляру {"action": "connect-instance"}
Отключение от облачного экземпляра {"action": "disconnect-instance"}
Сборка снимка {"action": "build", "resources": [{"type": "snapshot"}]}
Загрузка снимка {"action": "upload", "resources": [{"type": "snapshot"}]}

Общие действия

Помимо перечисленных выше действий, любой HTTP-запрос (POST, PATCH, PUT и DELETE) к API записывается с одним из следующих общих действий.

Вы также можете записывать запросы GET. Чтобы включить это, см. раздел Настройка журналирования аудита.

Действие Различающие поля
Запрос POST {"action": "post-action"}
Запрос PATCH {"action": "partial-update"}
Запрос PUT {"action": "update"}
Запрос DELETE {"action": "delete"}
Запрос GET {"action": "retrieve"}

Настройка журналирования аудита

Note

Функция аудита отключена по умолчанию.

Журналы аудита можно сохранять в файлы, отправлять на совместимую с Loki конечную точку или в стандартный логгер Grafana. Какой экспортёр использовать, выбирается в файле конфигурации.

Доступные варианты — file, loki и logger. Несколько режимов разделяются пробелами, например file loki.

Не все экспортёры доступны во всех вариантах развёртывания:

Экспортёр Grafana Enterprise Grafana Cloud
File Да (по умолчанию) Нет
Loki Да Да (по умолчанию)
Console Да Нет

По умолчанию содержимое дашбордов не попадает в журналы аудита, поскольку это может значительно увеличить размер журнала. Чтобы включить содержимое дашбордов, включите параметр log_dashboard_content.

Тела запросов и ответов при запросах к источникам данных также по умолчанию исключаются. Включение log_datasource_query_request_body или log_datasource_query_response_body значительно увеличивает объём журналов и может раскрыть конфиденциальные данные, такие как параметры запросов, учётные данные или персональные данные.

Прежде чем Grafana обработает DELETE /api/admin/users/{id}, она пытается зафиксировать отображаемое имя пользователя, а если отображаемое имя пусто — логин, чтобы журнал аудита мог сохранить его после успешного удаления. Параметр snapshot_timeout задаёт кооперативный контекстный срок для этого поиска. Хранилище пользователей должно учитывать отмену контекста, поэтому эта настройка не является жёсткой верхней границей задержки запроса. Если поиск завершается неудачей или обнаруживает истёкший срок, Grafana продолжает обработку запроса. Если удаление прошло успешно, журнал аудита не содержит resources[x].name.

ini
[auditing]
# Enable the auditing feature
enabled = false
# List of enabled loggers
loggers = file
# Keep dashboard content in the logs (request or response fields); this can significantly increase the size of your logs.
log_dashboard_content = false
# Whether to record data source queries' request body. This can significantly increase the size of your logs. Disabled by default.
log_datasource_query_request_body = false
# Whether to record data source queries' response body. This can significantly increase the size of your logs. Disabled by default.
log_datasource_query_response_body = false
# Keep requests and responses body; this can significantly increase the size of your logs.
verbose = false
# Write an audit log for every status code.
# By default it only logs the following ones: 2XX, 3XX, 401, 403 and 500.
log_all_status_codes = false
# Maximum response body (in bytes) to be audited; 500KiB by default.
# May help reducing the memory footprint caused by auditing.
max_response_size_bytes = 512000
# Timeout for resolving resource names before Grafana serves a request that
# may delete resources. Uses duration format, for example, 500ms or 2s.
# The default is 500ms.
snapshot_timeout = 500ms

У каждого экспортёра есть собственные поля конфигурации.

Экспортёр File

Note

Экспортёр File доступен только в Grafana Enterprise.

Журналы аудита сохраняются в файлы. Вы можете настроить папку, в которой будут сохраняться эти файлы. Журналы ротируются при превышении размера файла и в начале нового дня.

ini
[auditing.logs.file]
# Path to logs folder
path = data/log
# Maximum log files to keep
max_files = 5
# Max size in megabytes per log file
max_file_size_mb = 256

Экспортёр Loki

Журналы аудита отправляются на совместимую с Loki конечную точку по HTTP или gRPC. Этот экспортёр можно использовать для отправки журналов в Grafana Cloud Logs, в самостоятельно развёрнутый экземпляр Loki или в любой другой сервис, принимающий push API Loki.

Note

Вариант HTTP для экспортёра Loki доступен только в Grafana Enterprise версии 7.4 и более поздних.

ini
[auditing.logs.loki]
# Set the communication protocol to use with Loki (can be grpc or http)
type = grpc
# Set the address for writing logs to Loki
url = localhost:9095
# Defaults to true. If true, it establishes a secure connection to Loki
tls = true
# Set the tenant ID for Loki communication, which is disabled by default.
# The tenant ID is required to interact with Loki running in multi-tenant mode.
tenant_id =
# Only available for the HTTP client. Disabled by default.
# How long to wait before sending a request to Loki with the batch of events. Uses duration format, for example, 5s, 1m
# Whichever threshold is hit first between `batch_wait_duration` and `batch_size_bytes` triggers the batch to be sent to Loki.
# If the wait duration is very long and the `batch_size_bytes` is very high, events might take a long time to be sent.
# To enable batching, you must also set the `batch_size_bytes` configuration option.
batch_wait_duration =
# Only available for the HTTP client. Disabled by default.
# How many events, in bytes, to accumulate in a single batch before sending it to Loki.
# Whichever threshold is hit first between `batch_wait_duration` and `batch_size_bytes` triggers the batch to be sent to Loki.
# If you want to always wait for the `batch_wait_duration`, set `batch_size_bytes` to a very high number.
# To enable batching, you must also set the `batch_wait_duration` configuration option.
batch_size_bytes =

Если несколько экземпляров Grafana отправляют журналы в один и тот же сервис Loki или если вы используете Loki для журналов, не относящихся к аудиту, журналы аудита сопровождаются дополнительными метками, помогающими их опознать:

Метка Значение
host Имя хоста ОС, на котором запущен экземпляр Grafana
grafana_instance URL приложения
kind auditing

Если ваш экземпляр Loki требует basic-аутентификацию, укажите учётные данные в поле URL. Например:

ini
# Set the communication protocol to use with Loki (can be grpc or http)
type = http
# Set the address for writing logs to Loki
url = user:password@localhost:3000

Экспортёр Console

Note

Экспортёр Console доступен только в Grafana Enterprise.

Журналы аудита отправляются в стандартный логгер Grafana. Эти журналы используют логгер auditing.console и записываются на уровне debug. Как включить журналирование уровня debug, см. в разделе конфигурация журнала. Получение журналов аудита таким способом не рекомендуется для промышленной эксплуатации.