Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Аудит базы данных является важным компонентом требований к соответствию вашей организации. Отслеживая целевые действия, вы можете достичь базовых показателей безопасности. В гибком сервере Базы данных Azure для PostgreSQL можно настроить аудиты с помощью расширения PGaudit PG, как описано в журнале аудита в Базе данных Azure для PostgreSQL.
Одна из проблем заключается в использовании функции аудита вместе с аутентификацией Microsoft Entra ID, когда вы используете группы Microsoft Entra ID и хотите провести аудит действий отдельных участников группы. Проблема заключается в том, что участники группы входят в систему, используя свои личные токены доступа, но применяют имя группы в качестве имени пользователя.
Язык запросов Kusto (KQL) — это мощный язык запросов, управляемый конвейером, который позволяет запрашивать журналы служб Azure. KQL поддерживает запросы журналов Azure для быстрого анализа большого объема данных. В этой статье используйте KQL для запроса журналов Azure Postgres и извлечения сведений о пользователях идентификатора Microsoft Entra из журналов аудита.
Предпосылки
- Включение ведения журнала аудита — ведение журнала аудита в базе данных Azure для PostgreSQL
- Включите отправку журналов Azure Postgres в Службу аналитики журналов Azure — Настройка Log Analytics
-
log_line_prefixНастройте параметр сервера: в колонке "Параметры сервера" задайтеlog_line_prefixдля включения escape-адресовuser=%u,db=%d,session=%c,sess_time=%sв ту же последовательность, чтобы получить нужные результаты.- Перед:
log_line_prefix=%t-%c- - После:
log_line_prefix=%t-%c-user=%u,db=%d,session=%c,sess_time=%s
- Перед:
Запрос Kusto
Следующий запрос Kusto запрашивает AzureDiagnostics два раза.
Первый вложенный запрос находит все строки, содержащие строку Microsoft Entra ID connection authorized, и извлекает из них PrincipalName вместе со строкой SessionId журнала.
Второй вложенный запрос находит все журналы аудита.
Наконец, эти два подзапроса соединены по SessionId.
let lookbackTime = ago(3d);
let opindex = 3;
let startIndex = toscalar(range thirdIndex from opindex to opindex step 1
| project thirdIndex);
AzureDiagnostics
| where ResourceProvider == 'MICROSOFT.DBFORPOSTGRESQL'
| where TimeGenerated >= lookbackTime
| where Message contains 'Microsoft Entra ID connection authorized'
| extend SessionId = tostring(split(tostring(split(Message, 'session=')[-1]), ',sess_time')[-2])
| extend UPN = iff(Message contains 'UPN',tostring(split(tostring(split(Message, 'UPN=')[-1]), 'oid=')[-2]), '')
| extend appId = iff(Message contains 'appid', tostring(split(tostring(split(Message, 'appid=')[-1]), 'oid=')[-2]), '')
| extend PrincipalName = strcat(UPN, appId)
| project SessionId, PrincipalName
| join kind=leftouter
(
AzureDiagnostics
| where ResourceProvider == 'MICROSOFT.DBFORPOSTGRESQL'
| where TimeGenerated >= lookbackTime
| where Message contains 'AUDIT: SESSION'
| extend RoleName = tostring(split(tostring(split(Message, 'user=')[-1]), ',db')[-2])
| where RoleName !in ('azuresu', '[unknown]', 'postgres', '')
| extend SessionId = tostring(split(tostring(split(Message, 'session=')[-1]), ',sess_time')[-2])
| extend SubMessage = tostring(split(Message, 'SESSION,')[-1])
| extend splitArray = split(SubMessage, ',')
| extend SqlQueryP1 = tostring(split(tostring(split(Message, ',,,')[-1]), ',<')[-2])
| extend SqlQueryP2 = replace_string(tostring(split(SqlQueryP1, ',\"')[-1]), '"', '')
| extend SqlQueryP3 = tostring(split(Message, ',,,')[1])
| extend OperationType = tostring(splitArray[startIndex])
| extend SqlQuery = trim('"', case(OperationType == 'EXECUTE', SqlQueryP2, SqlQueryP1 == '', SqlQueryP3, SqlQueryP1))
)
on $left.SessionId == $right.SessionId
| project TimeGenerated, PrincipalName, RoleName, OperationType, SqlQuery
Пример результатов
Результирующая таблица выглядит следующим образом:
| Время генерации | Основное имя | НазваниеРоли | Тип операции | SqlQuery |
|---|---|---|---|---|
| 2025-12-12T16:25:05.104Z | user@example.com | ИмяПримераГруппы | SELECT | выберите * из pg_seclabels; |
| 2025-12-12T16:25:04.000Z | user@example.com | user@example.com | SELECT | выберите * из pg_seclabels; |
Если пользователь входит в роль группы, столбцы PrincipalName и RoleName отображают разные значения, например, в первой строке примера.
Значение PrincipalName определяет пользователя, выполнившего вход. Значение RoleName определяет роль в PostgreSQL, к которой пользователь получает доступ после входа.
PrincipalName — имя субъекта-пользователя (UPN) или AppId в зависимости от того, входит ли субъект-пользователь или субъект-служба.