MGGraph SignIn Logs

Das AzureAD protokolliert per Default nur die letzten 30 Tage aller "AuditLogs" und "SigniIn"-Logs mit. Wer mehr möchte, kann die Daten z.B. in Azure Sentinel ablegen. Mein Ziel war es aber, die Daten per Graph abzufragen und auf eigene Events zu parsen, z.B. eine Mail zu senden, wenn ein Benutzer in der Cloud neu angelegt wurde.

Azure Portal

Welche Sign-In und Audit-Logs vorliegen, kann ich im Azure Portal direkt einsehen. Unter der URL https://portal.azure.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/~/SignIns komme ich im Azure Portal direkt an die Übersicht, welche Anmeldungen erfolgt sind.

Hier gibt es sogar eine "Download"-Option, aber das ist ja keine passable Lösung für eine Automatsisierung.

Graph und MGGraph

Wo Microsoft diese Daten im Hintergrund ablegt, ist leider nicht öffentlich. Es könnte eine Datenbank pro Tenant oder vielleicht eine globale "Eventdatenbank" sein aber es gibt einen programmatischen Zugriff über die Graph-API

Ich könnte also einfach durch ein paar "Invoke-RestMethod-Aufrufe mir erst ein Token besorgen und dann die Informationen als JSON-Objekt abrufen. Aber über das MGGraph-Modul "Microsoft.Graph.Reports" der Graph PowerShell gibt es hier schon entsprechende Commandlets, die diese Aufgabe elegant kapseln:

PS C:\> get-command *-mgaudit*

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Function        Get-MgAuditLogDirectoryAudit                       1.9.5      Microsoft.Graph.Reports
Function        Get-MgAuditLogProvisioning                         1.9.5      Microsoft.Graph.Reports
Function        Get-MgAuditLogRestrictedSignIn                     1.9.5      Microsoft.Graph.Reports
Function        Get-MgAuditLogSignIn                               1.9.5      Microsoft.Graph.Reports

Aber direkt Aufrufen kann ich diese Commandlets erst einmal nicht.

App-Permission

Früher hätte ich nun ein "Dienstkonto" mit Kennwort angelegt, und mein Skript mit diesem Konto gestartet. Das ist mit MFA und Conditional Access natürlich nicht mehr so einfach möglich und auch nicht mehr gewollt. Stattdessen sollte ich meinem Code die entsprechenden Berechtigungen geben. Mein Programm bekommt einen "Benutzername" und ein Secret.. Ich registriert dazu im AzureAD eine Application mit einer AppID, einem Secret und den erforderlichen Berechtigungen:

Für meinen Code brauche ich aus der Seite dann die "Application (Cient) ID" und die "Directory (tenant) ID". Auf der Seite "Certificates & Sectes" lade ich die CER-Datei eines Zertifikats hoch, mit dem später die Anmeldung erfolgt. Details zur Anlage eines Zertifikats finden Sie auf MGGraph PowerShell.

Nun muss ich der App nur noch die erforderlichen Berechtigungen zuweisen. Laut Graph-Dokumentation brauche ich zum Lesen der Auditlogs folgende Rechte:

Entsprechend berechtige ich die Application und erteile meinen Admin Consent

Damit ist die App aus Sicht des AzureAD berechtigt und betriebsbereit.

Wenn ich doch einen Delegate-Zugriff mit einem Benutzer-Konto ausführen möchte, dann benötige ich andere Berechtigungen. Mein Token muss das Recht "Reports.Read.All" haben und in einer der folgenden Role Groups sein: Reports reader, Security reader, Security admin, Global reader oder Global admin

Anmelden

Nun muss ich nur noch im meinem Code die entsprechende Funktion ausführen. Das ist mit MGGraph sogar "interaktiv" möglich. Da ich zur Anmeldung ein Zertifikat nutze, dessen "private Key" sicher nicht auf der MSXFAQ zu finden ist, finden Sie hier kein Kennwort.

Connect-MgGraph `
   -AppId 508b98bf-64f9-4ee4-a28f-96c6d256fa7e `
   -TenantId 463e98ae-b7d4-4af2-8ef8-3eda0b4d8a7c `
   -CertificateThumbprint 815E2AD820B297DF4ED8D278CCE2D06EDAE35267


Get-Mgcontext

ClientId              : 508b98bf-64f9-4ee4-a28f-96c6d256fa7e
TenantId              : 463e98ae-b7d4-4af2-8ef8-3eda0b4d8a7c
CertificateThumbprint : 815E2AD820B297DF4ED8D278CCE2D06EDAE35267
Scopes                : {Directory.Read.All, AuditLog.Read.All}
AuthType              : AppOnly
AuthProviderType      : ClientCredentialProvider
CertificateName       :
Account               :
AppName               : MSXFAQSigninlogs
ContextScope          : Process
Certificate           :
PSHostVersion         : 7.2.4
ClientTimeout         : 00:05:00

Wenn Sie keine App registrieren wollen, dann können Sie natürlich auch einen Benutzer verwenden, der in einer der Role Groups Mitglied ist.

Connect-MgGraph -Scopes Reports.Read.All

Sie müssen als User natürlich ihre Zustimmung erteilen:

Das geht natürlich nur, wenn der Administrator diese Funktion zugelassen hat. Wenn Sie ein Admin-Konto nutzen, können Sie sogar Consent für die komplette Firma erteilen.

Für die Automatisierung eignet sich die Anmeldung als Benutzer allerdings nicht.

Daten abrufen

Nun kann ich mit "Get-MgAuditLogSignIn" und "Get-MgAuditLogSignIn" die Informationen abrufen. Ich würde erst einmal den letzten Eintrag zum Test abrufen. Und da ich mich gerade angemeldet habe, ist es sehr wahrscheinlich, dass ich auch genau diesen Event sehen. Hier die Anmeldung als "User"

PS C:\>Get-MgAuditLogSignIn -Top 1 | fl

AppDisplayName                   : Microsoft Graph PowerShell
AppId                            : 14d82eec-204b-4c2f-b7e8-296a70dab67e
AppliedConditionalAccessPolicies : {}
ClientAppUsed                    : Mobile Apps and Desktop clients
ConditionalAccessStatus          : success
CorrelationId                    : eae560d7-xxxx-xxxx-xxxx-46b96b84040a
CreatedDateTime                  : 15.06.2022 17:38:55
DeviceDetail                     : Microsoft.Graph.PowerShell.Models.MicrosoftGraphDeviceDetail
IPAddress                        : 94.31.80.223
Id                               : 0c4451ac-xxxx-xxxx-xxxx-42e59be09d00
IsInteractive                    : True
Location                         : Microsoft.Graph.PowerShell.Models.MicrosoftGraphSignInLocation
ResourceDisplayName              : Microsoft Graph
ResourceId                       : 00000003-0000-0000-c000-000000000000
RiskDetail                       : none
RiskEventTypes                   : {}
RiskEventTypesV2                 : {}
RiskLevelAggregated              : none
RiskLevelDuringSignIn            : none
RiskState                        : none
Status                           : Microsoft.Graph.PowerShell.Models.MicrosoftGraphSignInStatus
UserDisplayName                  : Admin (MSXFAQLAB)
UserId                           : 8a77045b-xxxx-xxxx-xxxx-c35681352c1e
UserPrincipalName                : admin@msxfaqlab.onmicrosoft.com
AdditionalProperties             : {}

In einem größeren Tenant wird die Liste nun natürlich deutlich länger und ohne Angabe eines Limits bekommen Sie die letzten 1000 Einträge. Wenn Sie wissen, nach was Sie suchen, dann sollten Sie schon bei der Abfrage einen Filter verwenden und nicht nachträglich mit "Where-Objekt" filtern.

Get-MgAuditLogSignIn -Filter "UserPrincipalName eq 'admin@msxfaq.de'"

Wenn Sie mehr als die 1000 Objekte abrufen wollen, dann können Sie ein "-all" anhängen. Dann bekommen Sie alle Logs der letzten 30 Tage. In meinem Test-Tenant bin ich da noch nicht in ein Throttling reingelaufen aber ich bin mir sicher, dass Graph hier vielleicht bremst. Ich würde dann wohl ein Paging mit einem Filter auf Zeiträume implementieren.

Über die PowerShell Funktion "Group-Object" lassen sich dann schon erste Verteilungen der genutzten Applikationen erstellen.

PS C:\> $signin = Get-MgAuditLogSignIn -Top 1000
PS C:\> $a | group AppDisplayName -NoElement

Count Name
----- ----
    3 Azure DevOps
    4 Azure Portal
    6 Dataverse
    3 Dynamics 365 Business Central
   11 Editor Browser Extension
    2 make.powerapps.com
    1 Microsoft Account Controls V2
    4 Microsoft Authentication Broker
    5 Microsoft Edge Enterprise New Tab Page
    3 Microsoft Graph PowerShell
    1 Microsoft Office
    2 Microsoft Power BI
   62 Microsoft Stream Portal
   85 Microsoft Teams
  216 Microsoft Teams Web Client
    2 Modern Workplace Tools
    5 My Profile
    3 NoSpamProxy
   50 Office 365 Exchange Online
   32 Office 365 SharePoint Online
    1 Office Delve
    2 Office Online Augmentation Loop SSO
   28 Office Online Core SSO
    3 Office Online Maker SSO
  103 Office365 Shell WCSS-Client
    3 OfficeHome
   12 OfficeShredderWacClient
    1 Outlook Mobile
    9 Powell-GraphApi
  246 PowerApps - apps.powerapps.com
    2 ProjectWorkManagement
   51 SharePoint Online Web Client Extensibility
   30 Windows Sign In
    5 Yammer
    4 Yammer Web

Ich habe hier nun keine IMAP/POP-Benutzer, aber auch die würden hier zu finden sein. Sie können aber recht einfach eine Abfrage machen, die alle Zugriffe auflistet, die nicht per Browser, Mobile App, Desktop Client oder ohne Angabe sind.

# Abruf der "Basic Auth" Anmeldungen der letzten 7 Tage
$startdate = (get-date).adddays(-7)
$sstartdate = $startdate.ToString("yyy-MM-dd")
$basicsignin = Get-MgAuditLogSignIn -Filter "CreatedDateTime ge $sstartdate and ClientAppUsed ne 'Browser' and ClientAppUsed ne 'Mobile Apps and Desktop clients' and ClientAppUsed ne ''"
$basicsignin

$basicsignin | group ClientAppUsed -NoElement | ft -autosize

Count Name
----- ----
    2 Exchange ActiveSync
    5 Exchange Online PowerShell
    6 Exchange Web Services
    8 IMAP4

$basicsignin | where {$_.ClientAppUsed -eq "IMAP4"} | group userprincipalname -NoElement

Count Name
----- ----
    5 user1@msxfaq.de.…
    3 prtgservice@msxfaq.de

#Wer nutzt noch ActiveSync mit Basic Auth
$basicsignin | where {$_.ClientAppUsed -eq "Exchange ActiveSync"} | group userprincipalname -NoElement | ft -AutoSize

# oder Exchange WebServices
$basicsignin | where {$_.ClientAppUsed -eq "Exchange Web Services"} | group userprincipalname -NoElement | ft -AutoSize

# Oder eine alte Exchange Online PowerShell
$basicsignin | where {$_.ClientAppUsed -eq "Exchange Online Powershell"} | group userprincipalname -NoElement | ft -AutoSize

					

So können Sie relativ einfach ermitteln, welche Anwender und Clients nach dem Abschalten der Exchange Basic Auth nicht mehr funktionieren werden.

Fehler

Auf den API-Beschreibungen zu Microsoft Graph wird erst einmal nicht explizit darauf hingewiesen aber um auf die API per Graph zugreifen zu können, müssen Sie eine AzureAD P1-Lizenz haben. Ich bekam auch diese Meldung direkt nach der Einrichtung der App.

S C:\> Get-MgAuditLogSignIn
Get-MgAuditLogSignIn_List: Neither tenant is B2C or tenant doesn't have premium license
PS C:\> Get-MgAuditLogSignIn
Get-MgAuditLogSignIn_List: Neither tenant is B2C or tenant doesn't have premium license

Allerdings hat mein Developer Tenant eine Microsoft 365 E5, in der auch AzureAD P1 enthalten ist. Es hat einfach ein paar Minuten gedauert, bis das Skript dann funktioniert hat. Vielleicht braucht Graph bei den ersten Aufrufen etwas, bis die Lizenzprüfung erfolgreich war.

Weitere Links