Granskningsloggning för Microsoft Entra ID-identiteter i Azure Database for PostgreSQL Flexible Server

Databasgranskningar är en viktig del av organisationens efterlevnadskrav. Genom att övervaka målaktiviteter kan du uppnå din säkerhetsbaslinje. I Azure Database for PostgreSQL – flexibel server kan du konfigurera granskningar med hjälp av PG-tillägget pgaudit, enligt beskrivningen i Granskningsloggning i Azure Database for PostgreSQL.

En utmaning är att använda granskningsfunktionen tillsammans med Microsoft Entra ID-autentisering när du använder Microsoft Entra-ID-grupper och vill granska enskilda gruppmedlemmars åtgärder. Den här utmaningen finns eftersom gruppmedlemmar loggar in med sina personliga åtkomsttoken men använder gruppnamnet som användarnamn.

Kusto Query Language (KQL) är ett kraftfullt pipelinedrivet, skrivskyddat frågespråk som gör det möjligt att köra frågor mot Azure-tjänstloggar. KQL stöder frågor mot Azure-loggar för att snabbt analysera en stor mängd data. I den här artikeln använder du KQL för att köra frågor mot Azure Postgres-loggar och extrahera användarinformation om Microsoft Entra-ID från granskningsloggar.

Förutsättningar

  1. Aktivera granskningsloggning – Granskningsloggning i Azure Database for PostgreSQL
  2. Aktivera Azure Postgres-loggar som ska skickas till Azure Log Analytics – Konfigurera och komma åt loggar
  3. Justera parametern log_line_prefix : Från bladet Parametrar anger du log_line_prefix så att den inkluderar escape-objekten user=%u,db=%d,session=%c,sess_time=%s i samma sekvens för att få önskat resultat.
    • Innan: log_line_prefix = %t-%c-
    • Efter: log_line_prefix = %t-%c-user=%u,db=%d,session=%c,sess_time=%s

Kusto-fråga

Följande Kusto-fråga använder AzureDiagnostics två gånger.
Den första underfrågan hittar alla rader som innehåller strängen Microsoft Entra ID connection authorized och extraherar, tillsammans med PrincipalName, SessionId från dessa loggar.
Den andra underfrågan hittar alla granskningsloggar.
Slutligen är dessa två underfrågor anslutna till 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

Exempelresultat

Den resulterande tabellen ser ut så här:

Tidpunkt för generering Huvudnamn Rollnamn Operationstyp SqlQuery
2025-12-12T16:25:05.104Z user@example.com ExampleGroupName SELECT välj * från pg_seclabels;
2025-12-12T16:25:04.000Z user@example.com user@example.com SELECT välj * från pg_seclabels;

Om användaren loggar in som en grupproll visar kolumnerna PrincipalName och RoleName olika värden, till exempel på den första raden i exemplet.
Värdet PrincipalName identifierar den användare som loggade in. Värdet RoleName identifierar rollen i PostgreSQL som användaren kommer åt efter inloggningen.

PrincipalName är antingen användarens huvudnamn (UPN) eller AppId beroende på om användarens huvudnamn eller tjänstens huvudnamn loggar in.