Microsoft365 ist mittlerweile ein wichtiger Bestandteil der IT-Umgebung vieler Unternehmen. Daher ist es wichtig, dass sich keine Unbefugten User der einloggen. Über die GraphAPI können riskante Logins erfasst werden. Im folgenden Artikel wird beschrieben, wie man diese Risky Logins mit Icinga2 prüft.
Vorbereitung auf MS365
Zuerst müssen wir auf der MS365-Oberfläche Zugänge erstellen: Wir loggen uns im MS365 Admin-Center ein und klicken auf „Identität“

Jetzt klicken wir auf Anwendungen > App-Registrierungen > neue Registrierung

Nun können wir eine neue App-Registrierung erstellen. Hierfür müssen wir einen Namen wählen und anschließend auf „registrieren“ klicken. Wir können dabei alle Standardeinstellungen behalten.
Jetzt notieren wir uns die Anwendungs und die Verzeichnis-ID

Jetzt klicken wir auf API-Berechtigungen > Microsoft Graph > Anwendungsberechtigungen. dort suchen wir nach IdentityRiskEvent.Read.All und setzten dann den Haken:

Zuletzt müssen wir einen neuen Clientschlüssel erstellen: Zertifikate und Geheimnisse > neuer geheimer Clientschlüssel. Nach dem Erstellen kopieren wir uns den Wert des neuen Schlüssels:

Check ins Icinga2 einbauen
Da wir nun einen GraphAPI Zugang erstellt haben, können wir jetzt den Check ins Icinga2 einbauen. Zunächst erstellen wir das Prüfskript:
#!/bin/bash
# Argumente parsen
while getopts "c:s:t:" opt; do
case $opt in
c)
clientId="$OPTARG"
;;
s)
clientSecret="$OPTARG"
;;
t)
tenantId="$OPTARG"
;;
\?)
echo "Ungültige Option: -$OPTARG"
exit 1
;;
esac
done
outputFile=$(mktemp)
exitok=false
exitwarn=false
exitcrit=false
# Token abrufen
token=$(curl -s -X POST https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d "grant_type=client_credentials&client_id=$clientId&client_secret=$clientSecret&scope=https://graph.microsoft.com/.default")
# Token parsen, um den Zugriffstoken zu extrahieren
accessToken=$(echo $token | jq -r '.access_token')
# Graph API-Anfrage
#curl -X GET https://graph.microsoft.com/v1.0/users?$select=id,displayName,riskLevel \
#curl -X GET https://graph.microsoft.com/identityProtection/riskDetections/users?$select=id,displayName,riskLevel \
curl -s -X GET https://graph.microsoft.com/v1.0/identityProtection/riskDetections \
-H "Authorization: Bearer $accessToken" \
> $outputFile
# Ausgabe
lowpriocheck=$(cat $outputFile | jq '.value[] | {userDisplayName, userPrincipalName, riskLevel, riskState, riskDetail, ipAddress, detectedDateTime}| select(.riskState != "remediated")| select(.riskState != "dismissed")| select(.riskState != "confirmedSafe")| select(.riskLevel == "low")')
medpriocheck=$(cat $outputFile | jq '.value[] | {userDisplayName, userPrincipalName, riskLevel, riskState, riskDetail, ipAddress, detectedDateTime}| select(.riskState != "remediated")| select(.riskState != "dismissed")| select(.riskState != "confirmedSafe")| select(.riskLevel == "medium")')
highpriocheck=$(cat $outputFile | jq '.value[] | {userDisplayName, userPrincipalName, riskLevel, riskState, riskDetail, ipAddress, detectedDateTime}| select(.riskState != "remediated")| select(.riskState != "dismissed")| select(.riskState != "confirmedSafe")| select(.riskLevel == "high")')
#if [ -z "$lowpriocheck" ]; then
# echo "Der Output ist leer."
#else
# echo "Der Output ist nicht leer."
#fi
if [ "$highpriocheck" ]; then
exitcrit=true
echo "Kritische Risiken:"
echo "$highpriocheck"
fi
if [ "$medpriocheck" ]; then
exitwarn=true
echo "Warnungs Risiken:"
echo "$medpriocheck"
fi
if [ "$lowpriocheck" ]; then
exitok=true
echo "Unwichtige Risiken:"
echo "$lowpriocheck"
fi
rm $outputFile
if [ $exitcrit == true ];then
exit 2
elif [ $exitwarn == true ];then
exit 1
elif [ $exitok == true ];then
exit 0
else
echo "Keine Risiken gefunden"
exit 0
fi
Dieses Skript muss einfach nur in den Standardordner für Checkskripte gelegt werden.
Jetzt erstellen wir den Command:
object CheckCommand "check_risky_logins" {
import "plugin-check-command"
command = [ PluginDir + "/check_risky_logins.sh" ]
arguments = {
"-c" = {value = "$clientid$"}
"-s" = {value = "$clientsecret$"}
"-t" = {value = "$tenantid$"}
}
}
Nun den Service:
/// *** "check_risky_logins" *** ///
apply Service "check_risky_logins" {
import "generic-service"
name = "check_risky_logins"
display_name = "MS365: Risky Logins"
check_command = "check_risky_logins"
/// ARGUMENTS ///
vars += host.vars.check_risky_logins
vars += host.vars.check_ms365_api
/// ASSIGN ///
assign where host.vars.check_risky_logins
assign where host.vars.check_ms365_api
ignore where host.vars.check_risky_logins.enable_check == false
ignore where host.vars.check_ms365_api.enable_check == false
}
Zuletzt erstellen wir den Eintrag im Host:
vars.check_ms365_api += {
clientid = "HIER_CLIENTID_EINFÜGEN"
clientsecret = "HIER_CLIENT_SECRET_EINFÜGEN"
tenantid = "HIER_TENANT_ID_EINFÜGEN"
}
Danach laden wir Icinga2 neu und der Check ist fertig.
Haben Sie noch Fragen zum Icinga2 oder anderen Monitoring Themen? Gerne unterstützen wir Sie mit unserem Know-How beim Aufbau und dem Betrieb Ihrer eigenen Icinga2-Installation, egal ob On Premise oder auf einem Cloud Server. Sprechen Sie uns an!
Besuchen Sie doch auch unsere Icinga Seite für mehr Informationen! Gerne unterstützen wir Sie bei Ihrem Vorhaben!
Weitere Icinga 2 Themen finden Sie hier.
- Risky Logins auf MS365 mit Icinga2 prüfen - 29. April 2025
- Integration von Jira in Icinga2 - 7. März 2025
- Plattenplatz auf Linux mit ncdu analysieren - 9. August 2022