שליטה ב- PowerShell Graph API: תובנות שקל לעקוב אחריהן

ממשק ה־Microsoft Graph API הוא שירות המאפשר לך לקרוא, לשנות ולנהל כמעט כל נגזרת של Azure AD ו־Office 365 תחת REST API אחד. במאמר זה, למד כיצד להמיר את ה־API שלך ל־PowerShell Graph API.

דרישות מוקדמות

אם ברצונך ללכת איתי במאמר זה, הקפד לעמוד בדרישות הבאות תחילה:

  • הפעלת Windows PowerShell 5.1 (זו הגרסה בה בדקתי. גרסאות אחרות יכולות לעבוד, אך אין הבטחה)
  • ערך Azure
  • אימות ל־Azure עם חשבון הניהול הכללי או עם הרשאות להרשמת אפליקציה במינוי והרשאת ניהול כללית כדי לאשר את בקשות ההרשמה של האפליקציה שלך.

יצירת זהות אפליקציה עבור Microsoft Graph API

כדי לגשת אל Microsoft Graph API, יש צורך קודם כל בזהות שתאפשר לך לקבל טוקן OAuth. זה נעשה בעיקר עם זהות אפליקציה שאתה יכול ליצור בפורטל של Azure. אתה יכול ליצור זהות אפליקציה דרך פורטל ה־Azure. כדי לעשות זאת:

  • עבור אל פורטל ה־Azure ונווט אל Active Directory של Azure.
  • לחץ על רישום אפליקציות תחת ניהול בתפריט השמאלי ולחץ על הכפתור רישום חדש.
Authenticating before creating the PowerShell Graph API
  • הזן שם לאפליקציה שלך ולחץ על רישום.
  • העתק את מזהה האפליקציה (Application Id) לשימוש מאוחר יותר.
Registering an application

יצירת סודות עבור Microsoft Graph API

שלום! הנה התרגום לעברית:

ניתן לאמת ל-Graph API באמצעות שני שיטות עיקריות: AppId/Secret ואימות המבוסס על תעודה. יהיה עליך לאמת כאשר אתה מתחבר ל-Graph API באמצעות PowerShell.

בוא נכסה איך לאמת עם שתי השיטות.

AppId/Secret

מזהה אפליקציה/סוד הוא כמו שם משתמש/סיסמה רגילים. מזהה האפליקציה מורכב מ-GUID במקום שם משתמש, והסיסמה היא פשוט מחרוזת אקראית.

כדי ליצור סוד, לחץ על תעודות & סודות בתפריט השמאלי וללחוץ על סוד לקוח חדש.

Creating a client secret

הזן תיאור לסוד ובחר מתי אתה רוצה שהוא יפוג. כעת זה רק עניין של לבקש הרשאה כדי שתוכל לגשת לנתונים שאתה רוצה.

תעודה

קיימת אפשרות ליצור תעודה עצמאית ולהעלות את מפתח הציבור שלה ל-Azure. זהו הדרך המועדפת והמאובטחת יותר לאימות.

תחילה, עליך ליצור תעודה עצמאית. למזלך, זה נעשה בקלות באמצעות PowerShell.

# שם השוכר שלך (יכול להיות משהו מתאר יותר גם)
$TenantName        = "contoso.onmicrosoft.com"

# היכן לייצא את התעודה ללא המפתח הפרטי
$CerOutputPath     = "C:\Temp\PowerShellGraphCert.cer"

# באיזה חנות תעודות ברצונך שתהיה
$StoreLocation     = "Cert:\CurrentUser\My"

# תאריך תפוגת התעודה החדשה
$ExpirationDate    = (Get-Date).AddYears(2)


# קופסה לקריאות נוחה
$CreateCertificateSplat = @{
    FriendlyName      = "AzureApp"
    DnsName           = $TenantName
    CertStoreLocation = $StoreLocation
    NotAfter          = $ExpirationDate
    KeyExportPolicy   = "Exportable"
    KeySpec           = "Signature"
    Provider          = "Microsoft Enhanced RSA and AES Cryptographic Provider"
    HashAlgorithm     = "SHA256"
}

# צור תעודה
$Certificate = New-SelfSignedCertificate @CreateCertificateSplat

# קבל את נתיב התעודה
$CertificatePath = Join-Path -Path $StoreLocation -ChildPath $Certificate.Thumbprint

# ייצא את התעודה ללא המפתח הפרטי
Export-Certificate -Cert $CertificatePath -FilePath $CerOutputPath | Out-Null

עכשיו, העלה את התעודה המאושרת עצמאית שייצאת ל-$CerOutputPath לאפליקציית ה-Azure שלך על ידי לחיצה על תעודות וסודות בתפריט השמאלי ולחיצה על העלאת תעודה.

Uploading a certificate

הוספת הרשאות לאפליקציה

נתינת הרשאות תקניות לאפליקציה היא חשובה – לא רק לפונקציונליות של האפליקציה שלך אלא גם לבטיחות. ידע על זה ועל (כמעט) כל הדברים האחרים ב- Microsoft Graph API ניתן למצוא ב-תיעוד.

פעם אחת שאני מקבל את זה מוכן, אני הולך לאסוף את כל אירועי האבטחה מהשוכר שלי. כדי להתיר את זה אני צריך SecurityEvents.Read.All כרשות מינימלית. עם זה אני יכול לאסוף ולפעול על אירועי נסיעה בלתי אפשריים, משתמשים המתחברים דרך VPN/TOR וכדומה.

כדי להוסיף את SecurityEvents.Read.All לאפליקציה שלך – לחץ על אישורי API ואז הוסף הרשאה. זה יציג לך לא רק את גרף ה-API אלא גם מספר רב של אפליקציות אחרות ב-Azure. רוב האפליקציות הללו קלות להתחבר אליהן פעם שאתה יודע איך להתחבר ל-Graf API של מיקרוסופט.

לחץ על מיקרוסופט גרף > רשות אפליקציה > אירועי אבטחה וסמן את SecurityEvents.Read.All. לאחר מכן לחץ על כפתור ההרשאה הוסף הרשאה.

ראית שעמוד ה נדרש אישור מנהל הוגדר ל כן על אותה הרשאה? זה אומר שמנהל שוכר צריך לאשר לפני שההרשאה מתווספת לאפליקציה.

Tenant admin permission approval

אם אתה מנהל גלובלי, לחץ על הענק אישור מנהל עבור או בקש מנהל גלובלי לאשר את זה. לבקש אישור מהמשתמש במקום מנהל שמגדיר רשות קריאה/כתיבה היא חלק גדול מאימות OAuth. אך זה מאפשר לנו לעקוף את זה עבור רוב הרשאות ב-Graph של מיקרוסופט.

כנראה שראית את זה כבר בפייסבוק או ב-Google: "האם אתה מאשר לאפליקציה X לגשת לפרופיל שלך?"

Granting admin consent

עכשיו אתה מוכן – בוא נתחבר ונקבל כמה נתונים!

רכוש טוקן גישה (מזהה יישום וסוד)

לצורך זה נצטרך לשלוח בקשה כדי לקבל טוקן גישה מכתובת אתר אוטוריזציה של Microsoft Graph OAuth. ובתוך גוף הבקשה עלינו לספק:

  • client_id – מזהה היישום שלך – מקודד ב-URL
  • client_secret – הסוד של היישום שלך – מקודד ב-URL
  • scope – URL מוקודד המציין את מה שתרצה לגשת אליו
  • grant_type – איזו שיטת אימות אתה משתמש

כתובת ה-URL עבור נקודת הסיום היא https://login.microsoftonline.com/<tenantname>/oauth2/v2.0/token. תוכל לבקש טוקן גישה עם PowerShell וממשק ה-Graph באמצעות קטע הקוד הבא.

# הגדר את AppId, הסוד וה- scope, שם הדייר שלך וכתובת ה-URL של נקודת הסיום
$AppId = '2d10909e-0396-49f2-ba2f-854b77c1e45b'
$AppSecret = 'abcdefghijklmnopqrstuv12345'
$Scope = "https://graph.microsoft.com/.default"
$TenantName = "contoso.onmicrosoft.com"

$Url = "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token"

# הוסף את System.Web כדי לבצע urlencode
Add-Type -AssemblyName System.Web

# צור את הגוף
$Body = @{
    client_id = $AppId
	client_secret = $AppSecret
	scope = $Scope
	grant_type = 'client_credentials'
}

# פזר את הפרמטרים עבור Invoke-Restmethod כדי לקבל קוד נקי יותר
$PostSplat = @{
    ContentType = 'application/x-www-form-urlencoded'
    Method = 'POST'
    # צור מחרוזת על ידי הצטרפות של bodylist עם '&'
    Body = $Body
    Uri = $Url
}

# בקש את הטוקן!
$Request = Invoke-RestMethod @PostSplat

רכוש טוקן גישה (באמצעות תעודה)

האימות לממשק ה-Graph של Microsoft עם תעודה קצת שונה מזרימת ה-AppId/Secret הרגילה. כדי לקבל טוקן גישה באמצעות תעודה עליך:

  1. צור כותרת טוקן רשת Java (JWT).
  2. צור גוף טוקן (Payload) JWT.
  3. חתום על כותרת וגוף ה-JWT עם התעודה המאושרת שנוצרה מראש. זה ייצור טוקן גישה שנוצר בעצמך שימושי לבקשת טוקן גישה של Microsoft Graph.
  4. צור גוף בקשה המכיל:
  • client_id=<application id>
  • client_assertion=<the JWT>
  • client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
  • scope=<URLEncoded scope>
  • grant_type=client_credentials
  1. בצע בקשת POST עם הגוף שנוצר לנקודת הסיום של OAuth עם Authorization=<JWT> בכותרת שלו.

איך לעשות זאת לא הייתה ברורה במסמכי Microsoft אבל הנה סקריפט PowerShell לביצוע זאת: מסמך המסמך

$TenantName = "<your tenant name>.onmicrosoft.com"
$AppId = "<your application id"
$Certificate = Get-Item Cert:\CurrentUser\My\<self signed and uploaded cert thumbprint>
$Scope = "https://graph.microsoft.com/.default"

# צור גיבוב base64 של התעודה
$CertificateBase64Hash = [System.Convert]::ToBase64String($Certificate.GetCertHash())

# צור חותמת זמן JWT לתפוגה
$StartDate = (Get-Date "1970-01-01T00:00:00Z" ).ToUniversalTime()
$JWTExpirationTimeSpan = (New-TimeSpan -Start $StartDate -End (Get-Date).ToUniversalTime().AddMinutes(2)).TotalSeconds
$JWTExpiration = [math]::Round($JWTExpirationTimeSpan,0)

# צור חותמת תקפות JWT להתחלת תוקף
$NotBeforeExpirationTimeSpan = (New-TimeSpan -Start $StartDate -End ((Get-Date).ToUniversalTime())).TotalSeconds
$NotBefore = [math]::Round($NotBeforeExpirationTimeSpan,0)

# צור כותרת JWT
$JWTHeader = @{
    alg = "RS256"
    typ = "JWT"
    # השתמש ב-CertificateBase64Hash והחלף/נטול כדי להתאים לקידוד web של base64
    x5t = $CertificateBase64Hash -replace '\+','-' -replace '/','_' -replace '='
}

# צור גוף של JWT
$JWTPayLoad = @{
    # איזה endpoint רשאי להשתמש ב-JWT זה
    aud = "https://login.microsoftonline.com/$TenantName/oauth2/token"

    # חותמת תפוגה
    exp = $JWTExpiration

    # מנפיק = היישום שלך
    iss = $AppId

    # זיהוי JWT: GUID אקראי
    jti = [guid]::NewGuid()

    # אין להשתמש לפני
    nbf = $NotBefore

    # נושא JWT
    sub = $AppId
}

# המר כותרת וגוף ל-base64
$JWTHeaderToByte = [System.Text.Encoding]::UTF8.GetBytes(($JWTHeader | ConvertTo-Json))
$EncodedHeader = [System.Convert]::ToBase64String($JWTHeaderToByte)

$JWTPayLoadToByte =  [System.Text.Encoding]::UTF8.GetBytes(($JWTPayload | ConvertTo-Json))
$EncodedPayload = [System.Convert]::ToBase64String($JWTPayLoadToByte)

# הצטרף כותרת וגוף עם "." כדי ליצור JWT תקף (לא חתום)
$JWT = $EncodedHeader + "." + $EncodedPayload

# קבל את אובייקט המפתח הפרטי של התעודה שלך
$PrivateKey = $Certificate.PrivateKey

# הגדר חתימת RSA ואלגוריתם גיבוב
$RSAPadding = [Security.Cryptography.RSASignaturePadding]::Pkcs1
$HashAlgorithm = [Security.Cryptography.HashAlgorithmName]::SHA256

# צור חתימה של ה-JWT
$Signature = [Convert]::ToBase64String(
    $PrivateKey.SignData([System.Text.Encoding]::UTF8.GetBytes($JWT),$HashAlgorithm,$RSAPadding)
) -replace '\+','-' -replace '/','_' -replace '='

# הצטרף לחתימה ל-JWT עם "."
$JWT = $JWT + "." + $Signature

# צור גיבוב עם פרמטרי גוף
$Body = @{
    client_id = $AppId
    client_assertion = $JWT
    client_assertion_type = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
    scope = $Scope
    grant_type = "client_credentials"

}

$Url = "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token"

# השתמש ב-JWT שנוצר בעצמך כאישור
$Header = @{
    Authorization = "Bearer $JWT"
}

# פרוץ את הפרמטרים עבור Invoke-Restmethod לקוד נקי יותר
$PostSplat = @{
    ContentType = 'application/x-www-form-urlencoded'
    Method = 'POST'
    Body = $Body
    Uri = $Url
    Headers = $Header
}

$Request = Invoke-RestMethod @PostSplat

הבנת פלט קבלת הרשאה לבקש

כאשר קיבלת טוקן גישה באמצעות מזהה יישום/סוד או באמצעות תעודה, תראה אובייקט עם ארבע מאפיינים.

  • token_type – איזה סוג של טוקן זה
  • expires_in – זמן בשניות שהטוקן גישה תקף
  • ext_expires_in – כמו expires_in אך לעמידות במקרה של תקלה בשירות הטוקן
  • access_token – עבור מה באנו

לאחר מכן, תיצור כותרת באמצעות token_type ו-access_token ותתחיל לבצע בקשות עם PowerShell ל-Microsoft Graph API.

ביצוע בקשות ל-Microsoft Powershell Graph API

כעת התחל לבצע כמה בקשות ל-API.

עוברים עם הדוגמה שלנו, תזדקק ל-URL לרשימת אזהרות אבטחה. זכור להשתמש במסמכי ה-API של Microsoft Graph לצפיה במה שנדרש.

במקרה זה, תזדקק לכותרת עם Authorization=Bearer <access_token> ובקשת GET לנקודת הקצה של אזהרות ה-Graph API. כך תעשה זאת עם PowerShell.

# יצירת כותרת
$Header = @{
    Authorization = "$($Request.token_type) $($Request.access_token)"
}

$Uri = "https://graph.microsoft.com/v1.0/security/alerts"

# אחזור את כל האזהרות בטחון
$SecurityAlertsRequest = Invoke-RestMethod -Uri $Uri -Headers $Header -Method Get -ContentType "application/json"

$SecurityAlerts = $SecurityAlertsRequest.Value

כעת, אם יש לך אזהרות אבטחה במשתנה $SecurityAlerts, זה צריך לראות משהו דומה לזה:

$SecurityAlerts | select eventDateTime,Title

eventDateTime                title
-------------                -----
2019-08-05T17:59:47.6271981Z Atypical travel
2019-08-05T08:23:01.7325708Z Anonymous IP address
2019-08-05T08:23:55.5000456Z Anonymous IP address
2019-08-04T22:06:51.063797Z  Anonymous IP address
2019-08-04T21:56:10.981437Z  Anonymous IP address
2019-08-08T09:30:00Z         Creation of forwarding/redirect rule
2019-07-19T13:30:00Z         eDiscovery search started or exported
2019-07-19T08:00:00Z         eDiscovery search started or exported

בדיקת התראת אבטחה יחידה כJSON תראה כך:

"id":  "censored",
    "azureTenantId":  "censored",
    "azureSubscriptionId":  "censored",
    "riskScore":  null,
    "tags":  [

             ],
    "activityGroupName":  null,
    "assignedTo":  null,
    "category":  "AnonymousLogin",
    "closedDateTime":  null,
    "comments":  [

                 ],
    "confidence":  null,
    "createdDateTime":  "2019-08-08T09:46:59.65722253Z",
    "description":  "Sign-in from an anonymous IP address (e.g. Tor browser, anonymizer VPNs)",
    "detectionIds":  [

                     ],
    "eventDateTime":  "2019-08-08T09:46:59.65722253Z",
    "feedback":  null,
    "lastModifiedDateTime":  "2019-08-08T09:54:30.7256251Z",
    "recommendedActions":  [

                           ],
    "severity":  "medium",
    "sourceMaterials":  [

                        ],
    "status":  "newAlert",
    "title":  "Anonymous IP address",
    "vendorInformation":  {
                              "provider":  "IPC",
                              "providerVersion":  null,
                              "subProvider":  null,
                              "vendor":  "Microsoft"
                          },
    "cloudAppStates":  [

                       ],
    "fileStates":  [

                   ],
    "hostStates":  [

                   ],
    "historyStates":  [

                      ],
    "malwareStates":  [

                      ],
    "networkConnections":  [

                           ],
    "processes":  [

                  ],
    "registryKeyStates":  [

                          ],
    "triggers":  [

                 ],
    "userStates":  [
                       {
                           "aadUserId":  "censored",
                           "accountName":  "john.doe",
                           "domainName":  "contoso.com",
                           "emailRole":  "unknown",
                           "isVpn":  null,
                           "logonDateTime":  "2019-08-08T09:45:59.6174156Z",
                           "logonId":  null,
                           "logonIp":  "censored",
                           "logonLocation":  "Denver, Colorado, US",
                           "logonType":  null,
                           "onPremisesSecurityIdentifier":  null,
                           "riskScore":  null,
                           "userAccountType":  null,
                           "userPrincipalName":  "[email protected]"
                       }
                   ],
    "vulnerabilityStates":  [

                            ]
}

הבנת וניהול פלט API בדפוסים

API של Microsoft Graph מוגבל לפי פונקציה בכמה פריטים הוא יחזיר. המגבלה הזו היא לפי פונקציה אך נניח שהיא 1000 פריטים. זה אומר שתוכלו לקבל מרבית 1000 פריטים בבקשתכם.

כאשר מתקבלת עד המגבלה זו ישתמש בדפוס על מנת למסור את שאר הפריטים. הוא עושה זאת על ידי הוספת המאפיין @odata.nextLink לתשובת הבקשה שלך. @odata.nextLink מכיל URL שבו תוכלו לקרוא כדי לקבל את הדף הבא של בקשתך.

ניתן לעבור על כל הפריטים על ידי בדיקה של המאפיין הזה ושימוש בלולאה:

$Uri = "https://graph.microsoft.com/v1.0/auditLogs/signIns"

# קבל את כל ההתראות לגבי אבטחה
$AuditLogRequest = Invoke-RestMethod -Uri $Uri -Headers $Header -Method Get -ContentType "application/json"

$AuditLogs = @()
$AuditLogs+=$AuditLogRequest.value

while($AuditLogRequest.'@odata.nextLink' -ne $null) {
    $AuditLogRequest += Invoke-RestMethod -Uri $AuditLogRequest.'@odata.nextLink' -Headers $Header -Method Get -ContentType "application/json"
}

מסקנה

לאחר שתלמדו כיצד לאמת ל-Graph API של Microsoft, זה די פשוט לאסוף ממנו נתונים. זו שירות עוצמתי שמשמש פחות ממה שצריך.

במזל רב ישנם הרבה מודולים שם שכבר משתמשים ב-API של Microsoft Graph אך כדי לענות על צרכים משלכם עשויים להיות עליכם ליצור מודול משלכם עבור זה. באמצעות הכישורים שלמדתם במאמר זה, תצליחו היטב בדרככם.

למידע נוסף על שליטה בגישה לאורחים ב-Office 365, כתבתי מאמר מפורט בבלוג שלי. אני ממליץ לך ל בדוק אותו.

Source:
https://adamtheautomator.com/powershell-graph-api/