Protokolování auditu pro objekty zabezpečení Microsoft Entra ID ve flexibilním serveru Azure Database for PostgreSQL

Audity databází jsou důležitou součástí požadavků vaší organizace na dodržování předpisů. Monitorováním cílových aktivit můžete dosáhnout standardních hodnot zabezpečení. Na flexibilním serveru Azure Database for PostgreSQL můžete audity nastavit pomocí rozšíření pgaudit PG, jak je popsáno v protokolování auditu ve službě Azure Database for PostgreSQL.

Jednou z výzev je použití funkce auditování spolu s ověřováním ID Microsoft Entra, když používáte skupiny ID Microsoft Entra a chcete auditovat akce jednotlivých členů skupiny. Tato výzva existuje, protože se členové skupiny přihlašují pomocí svých osobních přístupových tokenů, ale jako uživatelské jméno používají název skupiny.

Dotazovací jazyk Kusto (KQL) je výkonný dotazovací jazyk založený na kanálech, který je pouze pro čtení a umožňuje dotazování protokolů služeb Azure. KQL podporuje dotazování protokolů Azure k rychlé analýze velkého objemu dat. Pro účely tohoto článku použijte KQL k dotazování protokolů Azure Postgres a extrahování informací o uživatelských údajech Microsoft Entra ID z protokolů auditu.

Požadavky

  1. Povolení protokolování auditu – Protokolování auditu ve službě Azure Database for PostgreSQL
  2. Povolení odesílání protokolů Postgres Azure do Azure Log Analytics – Konfigurace a přístupové protokoly
  3. log_line_prefix Upravte parametr: V okně Parametry nastavtelog_line_prefix, aby obsahoval řídicí znaky user=%u,db=%d,session=%c,sess_time=%s ve stejné sekvenci, aby se získaly požadované výsledky.
    • Před: log_line_prefix = %t-%c-
    • Po: log_line_prefix = %t-%c-user=%u,db=%d,session=%c,sess_time=%s

Dotaz pro Kusto

Následující dotaz Kusto dotazuje AzureDiagnostics dvakrát.
První poddotaz najde všechny řádky, které obsahují řetězec Microsoft Entra ID connection authorized , a extrahuje PrincipalName z těchto řádků protokolu společně s SessionId.
Druhý poddotaz najde všechny protokoly auditu.
Nakonec jsou tyto dva poddotazy spojené na 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

Příklady výsledku

Výsledná tabulka vypadá takto:

Čas vygenerování HlavníNázev RoleName (Název role) Typ operace SqlQuery
2025-12-12T16:25:05.104Z user@example.com ExampleGroupName SELECT vyberte * z pg_seclabels;
2025-12-12T16:25:04.000Z user@example.com user@example.com SELECT vyberte * z pg_seclabels;

Pokud se uživatel přihlásí jako skupinová role, sloupce PrincipalName a RoleName zobrazí různé hodnoty, například v prvním řádku příkladu.
Tato PrincipalName hodnota identifikuje uživatele, který se přihlásil. Tato RoleName hodnota identifikuje roli v PostgreSQL, ke které uživatel přistupuje po přihlášení.

PrincipalName je buď uživatelské hlavní jméno (UPN) nebo AppId v závislosti na tom, zda se přihlašuje uživatelský instanční objekt nebo instanční objekt služby.