API'nizi PowerShell Graph API'sine dönüştürme


Microsoft Graph API, Azure AD ve Office 365'in neredeyse her yönünü tek bir REST API uç noktası altında okumanıza, değiştirmenize ve yönetmenize olanak tanıyan bir hizmettir. Bu makalede API'nizi PowerShell Graph API'sine nasıl dönüştüreceğinizi öğrenin.

Önkoşullar

Bu makaleyi benimle birlikte takip etmek istiyorsanız öncelikle aşağıdaki kriterleri karşıladığınızdan emin olun:

  • Windows PowerShell 5.1 çalıştırma (Bu, test ettiğim sürümdür. Diğer sürümler çalışabilir ancak garanti edilmez)
  • Azure kiracısı
  • Abonelikte genel yönetici izinlerine veya uygulama kayıt izinlerine sahip bir hesapla ve uygulama kayıt isteklerinizi kabul edecek genel bir yöneticiyle Azure'da kimliği doğrulanmıştır.

Microsoft Graph API için Uygulama Kimliği Oluşturma

Microsoft Graph API'ye erişmek için öncelikle bir OAuth belirteci almak üzere bir kimliğe ihtiyacınız vardır. Bu öncelikle Azure Portal'da oluşturabileceğiniz bir uygulama kimliğiyle yapılır. Azure portalı aracılığıyla bir uygulama kimliği oluşturabilirsiniz. Böyle yaparak:

  • Azure Portal'a gidin ve Azure Active Directory'ye gidin.
  • Soldaki menüdeki Yönet altında Uygulama Kayıtları'nı tıklayın ve Yeni kayıt düğmesini tıklayın.
  • Uygulamanız için bir ad girin ve Kaydol'u tıklayın.
  • Uygulama Kimliği kılavuzunu daha sonra kullanmak üzere kopyalayın.

Microsoft Graph API'si için Gizli Diziler Oluşturma

Graph API'de iki ana yöntemle kimlik doğrulaması yapabilirsiniz: AppId/Secret ve sertifika tabanlı kimlik doğrulama. PowerShell ile grafik API'sine bağlanırken kimlik doğrulamanız gerekecektir.

Her iki yöntemle de kimlik doğrulamanın nasıl yapılacağını ele alalım.

Uygulama Kimliği/Gizli

Bir uygulama kimliği/sırrı, normal bir kullanıcı adı/şifre gibidir. Uygulama kimliği, kullanıcı adı yerine bir GUID'den oluşur ve parola yalnızca rastgele bir dizedir.

Bir sır oluşturmak için soldaki menüde Sertifikalar ve sırlar'ı tıklayın ve Yeni müşteri sırrı'na basın.

Sır için bir açıklama girin ve süresinin ne zaman dolmasını istediğinizi seçin. Artık istediğiniz verilere erişebilmeniz için izin istemeniz yeterli.

Sertifika

Kendinden imzalı bir sertifika oluşturma ve bunun ortak anahtarını Azure'a yükleme olanağı vardır. Bu, kimlik doğrulamanın tercih edilen ve daha güvenli yoludur.

Öncelikle kendinden imzalı bir sertifika oluşturmanız gerekir. Neyse ki bu PowerShell ile kolayca yapılabilir.

# Your tenant name (can something more descriptive as well)
$TenantName        = "contoso.onmicrosoft.com"

# Where to export the certificate without the private key
$CerOutputPath     = "C:\Temp\PowerShellGraphCert.cer"

# What cert store you want it to be in
$StoreLocation     = "Cert:\CurrentUser\My"

# Expiration date of the new certificate
$ExpirationDate    = (Get-Date).AddYears(2)


# Splat for readability
$CreateCertificateSplat = @{
    FriendlyName      = "AzureApp"
    DnsName           = $TenantName
    CertStoreLocation = $StoreLocation
    NotAfter          = $ExpirationDate
    KeyExportPolicy   = "Exportable"
    KeySpec           = "Signature"
    Provider          = "Microsoft Enhanced RSA and AES Cryptographic Provider"
    HashAlgorithm     = "SHA256"
}

# Create certificate
$Certificate = New-SelfSignedCertificate @CreateCertificateSplat

# Get certificate path
$CertificatePath = Join-Path -Path $StoreLocation -ChildPath $Certificate.Thumbprint

# Export certificate without private key
Export-Certificate -Cert $CertificatePath -FilePath $CerOutputPath | Out-Null

Şimdi, $CerOutputPath'e aktardığınız kendinden imzalı sertifikayı, sol menüdeki Sertifikalar ve sırlar'a tıklayıp Sertifika yükle'ye basarak Azure Uygulamanıza yükleyin. .

Uygulamaya izinler ekleme

Uygulamaya uygun izinlerin verilmesi yalnızca uygulamanızın işlevselliği açısından değil aynı zamanda güvenlik açısından da önemlidir. Bununla ilgili bilgi ve Microsoft Graph API'sindeki (neredeyse) diğer her şey belgelerde bulunabilir.

Bu kurulumu tamamladıktan sonra tüm güvenlik olaylarını kiracımdan toplayacağım. Bunu yapabilmem için minimum izin olarak SecurityEvents.Read.All'e ihtiyacım var. Bununla İmkansız Seyahat olaylarını, VPN/TOR aracılığıyla bağlanan kullanıcıları vb. toplayıp bunlar hakkında harekete geçebiliyorum.

SecurityEvents.Read.All'i uygulamanıza eklemek için - API İzinleri'ni ve ardından İzin Ekle'yi tıklayın. Bu size yalnızca Graph API'yi değil aynı zamanda Azure'daki bir sürü başka uygulamayı da sunacaktır. Microsoft Graph API'sine nasıl bağlanacağınızı öğrendikten sonra bu uygulamaların çoğuna bağlanmak kolaydır.

Microsoft Graph > Uygulama İzinleri > Güvenlik Olayları'nı tıklayın ve SecurityEvents.Read.All'i kontrol edin. Bundan sonra İzin Ekle düğmesine basın.

Bu izinde Yönetici izni gerekli sütununun Evet olarak ayarlandığını gördünüz mü? Bu, izin uygulamaya eklenmeden önce kiracı yöneticisinin onaylaması gerektiği anlamına gelir.

Genel yöneticiyseniz Yönetici izni ver seçeneğine basın veya Genel Yöneticiden bunu onaylamasını isteyin. Yalnızca okuma/yazma iznini ayarlamak için yönetici yerine kullanıcıdan izin istemek, OAuth kimlik doğrulamasının büyük bir parçasıdır. Ancak bu, Microsoft Graph'taki çoğu izin için bunu atlamamıza olanak tanır.

Muhtemelen bunu Facebook'ta veya Google'da zaten görmüşsünüzdür: "X uygulamasının profilinize erişmesine izin veriyor musunuz?"

Artık hazırsınız; hadi giriş yapıp biraz veri alalım!

Erişim Belirteci Edinme (Uygulama Kimliği ve Sırrı)

Bunun için bir Microsoft Graph OAuth uç noktasından erişim belirteci almak üzere bir istek göndermemiz gerekecek. Ve bu talebin metninde şunları sağlamamız gerekiyor:

  • client_id - Uygulama Kimliğiniz - url kodlu
  • client_secret - Uygulamanızın sırrı - url kodlu
  • kapsam - Neye erişmek istediğinizi belirten URL kodlu bir URL
  • grant_type - Hangi kimlik doğrulama yöntemini kullanıyorsunuz?

Uç noktanın URL'si https://login.microsoftonline.com//oauth2/v2.0/token'dir. Aşağıdaki kod parçacığını kullanarak PowerShell ve Graph API ile erişim belirteci talep edebilirsiniz.

# Define AppId, secret and scope, your tenant name and endpoint 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"

# Add System.Web for urlencode
Add-Type -AssemblyName System.Web

# Create body
$Body = @{
    client_id = $AppId
	client_secret = $AppSecret
	scope = $Scope
	grant_type = 'client_credentials'
}

# Splat the parameters for Invoke-Restmethod for cleaner code
$PostSplat = @{
    ContentType = 'application/x-www-form-urlencoded'
    Method = 'POST'
    # Create string by joining bodylist with '&'
    Body = $Body
    Uri = $Url
}

# Request the token!
$Request = Invoke-RestMethod @PostSplat

Erişim Jetonu Alın (Sertifika Kullanarak)

Sertifikayla Microsoft Graph API'sinin kimlik doğrulaması, normal AppId/Secret akışından biraz farklıdır. Sertifika kullanarak erişim belirteci almak için şunları yapmanız gerekir:

  1. Bir Java Web Token (JWT) başlığı oluşturun.
  2. Bir JWT yükü oluşturun.
  3. JWT üstbilgisini VE yükünü önceden oluşturulan kendinden imzalı sertifikayla imzalayın. Bu, Microsoft Graph erişim belirteci istemek için kullanılan, kendi kendine oluşturulmuş bir erişim belirteci oluşturacaktır.
  4. Aşağıdakileri içeren bir istek gövdesi oluşturun:
    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. Başlığında Authorization= ile gövde ile oauth uç noktasına bir gönderi isteği yapın.

Bunun nasıl yapılacağı Microsoft'un belgelerinde açık değildi ancak işte bunu gerçekleştirmek için PowerShell betiği:

$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"

# Create base64 hash of certificate
$CertificateBase64Hash = [System.Convert]::ToBase64String($Certificate.GetCertHash())

# Create JWT timestamp for expiration
$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)

# Create JWT validity start timestamp
$NotBeforeExpirationTimeSpan = (New-TimeSpan -Start $StartDate -End ((Get-Date).ToUniversalTime())).TotalSeconds
$NotBefore = [math]::Round($NotBeforeExpirationTimeSpan,0)

# Create JWT header
$JWTHeader = @{
    alg = "RS256"
    typ = "JWT"
    # Use the CertificateBase64Hash and replace/strip to match web encoding of base64
    x5t = $CertificateBase64Hash -replace '\+','-' -replace '/','_' -replace '='
}

# Create JWT payload
$JWTPayLoad = @{
    # What endpoint is allowed to use this JWT
    aud = "https://login.microsoftonline.com/$TenantName/oauth2/token"

    # Expiration timestamp
    exp = $JWTExpiration

    # Issuer = your application
    iss = $AppId

    # JWT ID: random guid
    jti = [guid]::NewGuid()

    # Not to be used before
    nbf = $NotBefore

    # JWT Subject
    sub = $AppId
}

# Convert header and payload to 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)

# Join header and Payload with "." to create a valid (unsigned) JWT
$JWT = $EncodedHeader + "." + $EncodedPayload

# Get the private key object of your certificate
$PrivateKey = $Certificate.PrivateKey

# Define RSA signature and hashing algorithm
$RSAPadding = [Security.Cryptography.RSASignaturePadding]::Pkcs1
$HashAlgorithm = [Security.Cryptography.HashAlgorithmName]::SHA256

# Create a signature of the JWT
$Signature = [Convert]::ToBase64String(
    $PrivateKey.SignData([System.Text.Encoding]::UTF8.GetBytes($JWT),$HashAlgorithm,$RSAPadding)
) -replace '\+','-' -replace '/','_' -replace '='

# Join the signature to the JWT with "."
$JWT = $JWT + "." + $Signature

# Create a hash with body parameters
$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"

# Use the self-generated JWT as Authorization
$Header = @{
    Authorization = "Bearer $JWT"
}

# Splat the parameters for Invoke-Restmethod for cleaner code
$PostSplat = @{
    ContentType = 'application/x-www-form-urlencoded'
    Method = 'POST'
    Body = $Body
    Uri = $Url
    Headers = $Header
}

$Request = Invoke-RestMethod @PostSplat

Erişim Jetonu Çıkışını İstemeyi Anlama

Uygulama kimliği/gizli dizi veya sertifika aracılığıyla bir erişim belirteci aldıktan sonra dört özelliğe sahip bir nesne görmelisiniz.

  • token_type - Ne tür bir jeton?
  • expires_in - Erişim belirtecinin geçerli olduğu saniye cinsinden süre
  • ext_expires_in - expires_in gibi ancak belirteç hizmeti kesintisi durumunda esneklik için
  • access_token - Ne için geldik?

Daha sonra token_type ve access_token kullanarak bir başlık oluşturacak ve PowerShell ile Microsoft Graph API'sine istekte bulunmaya başlayacaksınız.

Microsoft Graph API'sine İstekte Bulunma

Şimdi API'ye bazı isteklerde bulunmaya başlayın.

Örneğimize göre, öncelikle güvenlik uyarılarını listelemek için URL'ye ihtiyacınız olacak. Neyin gerekli olduğunu görmek için Microsoft Graph API belgelerini kullanmayı unutmayın.

Bu durumda, Authorization=Bearer içeren bir başlığa ve Graph API Alerts uç noktasına yönelik bir GET isteğine ihtiyacınız vardır. Bunu PowerShell ile nasıl yapacağınız aşağıda açıklanmıştır.

# Create header
$Header = @{
    Authorization = "$($Request.token_type) $($Request.access_token)"
}

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

# Fetch all security alerts
$SecurityAlertsRequest = Invoke-RestMethod -Uri $Uri -Headers $Header -Method Get -ContentType "application/json"

$SecurityAlerts = $SecurityAlertsRequest.Value

Artık $SecurityAlerts değişkeninde herhangi bir güvenlik uyarınız varsa, bunun şöyle görünmesi gerekir:

$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

Tek bir güvenlik uyarısını JSON olarak incelemek şu şekilde görünecektir:

"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 "
                       }
                   ],
    "vulnerabilityStates":  [

                            ]
}

API Çıkış Sayfalamayı Anlama ve Yönetme

Microsoft Graph API'nin, işlev başına kaç öğe döndüreceğine ilişkin bir sınırı vardır. Bu sınır fonksiyon başınadır ancak 1000 öğe diyelim. Bu, isteğinizde yalnızca maksimum 1000 öğe alabileceğiniz anlamına gelir.

Bu sınıra ulaşıldığında, geri kalan öğeleri teslim etmek için çağrıyı kullanacaktır. Bunu isteğinizin cevabına @odata.nextLink özelliğini ekleyerek yapar. @odata.nextLink, isteğinizin sonraki sayfasına ulaşmak için arayabileceğiniz bir URL içerir.

Bu özelliği kontrol ederek ve bir döngü kullanarak tüm öğeleri okuyabilirsiniz:

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

# Fetch all security alerts
$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"
}

Çözüm

Graph API'de nasıl kimlik doğrulaması yapacağınızı öğrendikten sonra ondan veri toplamak oldukça kolaydır. Olması gerekenden çok daha az kullanılan güçlü bir hizmettir.

Neyse ki Microsoft Graph API'yi kullanmak için halihazırda birçok modül var ancak kendi ihtiyaçlarınızı karşılamak için kendi modülünüzü oluşturmanız gerekebilir. Bu makalede öğrendiğiniz becerileri kullanarak yolunuza devam etmelisiniz.

Office 365'te misafir erişimini kontrol etme hakkında daha fazla bilgi için blogumda detaylı bir makale yazdım, göz atmanızı tavsiye ederim.

İlgili makaleler