LoginSignup
7
7

More than 1 year has passed since last update.

Office 365 の監査ログを Microsoft Sentinel に格納する - Office 365 Management API と Data Collector API (PowerShell 利用版)

Last updated at Posted at 2020-03-02

本記事の内容

本記事では、Office 365 の監査ログを Office 365 Management APIAudit.Generalサブスクリプション)と Data Collector API を利用して、Azure Log Analytics (Microsoft Sentinel) に格納していきます。本記事では PowerShell を利用して行っていきますが、他の言語でも可能です。

2022年7月時点では、Office 365 のログのうち、Microsoft Sentinel に標準のコネクターで格納できるのは SherePoint/OneDriveとExchange, Teams の監査ログのみのため、それ以外のログをどう格納していくことができるか見ていきます。

本記事に先立ち

本記事は、下記記事の内容をベースに進めていきます。Office 365 Management API の AADでのアクセス許可の設定やAudit.General サブスクリプション、Log Analyticsのワークスペースの作成などは事前に行っているものとします。

Office 365 Management API の使い方 with PowerShell
Azure Log Analytics Data Collector API で データを Log Analytics (Azure Sentinel) に格納する with PowerShell

また、下記の GitHub レポジトリの内容をベースにしています。
Deploy Function App for getting Office 365 Management API data into Azure Sentinel

PowerShell コード

基本的にはManagement APIによるデータの取得から、Data Collector API によるログ格納まで一気に実行するコードですが、分けてご紹介します。

変数の定義

まず、Office 365 Management API と Log Analytics Data Collector API を利用するために必要な変数を定義しておきます。

$ClientID = "<GUID> from AAD App Registration"
$ClientSecret = "<clientSecret> from AAD App Registrtion"
$loginURL = "https://login.microsoftonline.com/"
$tenantdomain = "<domain>.onmicrosoft.com"
$TenantGUID = "<tenantguid> from AAD"
$resource = "https://manage.office.com"
$workspaceID ="<ID> from Log Analytics workspace>"
$workspaceKey = "<key> from Log Analytics workspace>"
$customLogName = "Office365ManagementAPI"

AAD アクセストークンの取得

次に、AADアクセストークンを取得します。

$body = @{grant_type="client_credentials";resource=$resource;client_id=$ClientID;client_secret=$ClientSecret}
$oauth = Invoke-RestMethod -Method Post -Uri $loginURL/$tenantdomain/oauth2/token?api-version=1.0 -Body $body
$headerParams = @{'Authorization'="$($oauth.token_type) $($oauth.access_token)"}

Office 365 Management API のデータを取る際に必要な時間の情報を定義

次に、Office 365 Management API のデータを取る際に必要な時間の情報を定義します。過去7日以内かつ、startTime と endTime の間が24時間以内になるようにします。

$currentUTCtime = (Get-Date).ToUniversalTime()
$endTime = $currentUTCtime.AddHours(-60) | Get-Date -Format yyyy-MM-ddThh:mm:ss
$startTime = $currentUTCtime.AddHours(-84) | Get-Date -Format yyyy-MM-ddThh:mm:ss
$contentTypes = "Audit.General"
$recordTypes = 0

Office 365 Management API と Data Collector API の実行

Office 365 Management API を実行し、データを取得した後、そのイベントごとに Foreach ループを用いて、Data Collector API (function Write-OMSLogfile) で Log Analytics にデータを格納します。

$contentTypes = $contentTypes.split(",")
    #Loop for each content Type like Audit.General
    foreach($contentType in $contentTypes){
        $listAvailableContentUri = "https://manage.office.com/api/v1.0/$tenantGUID/activity/feed/subscriptions/content?contentType=$contentType&PublisherIdentifier=$publisher&startTime=$startTime&endTime=$endTime"
        do {
            #List Available Content
            $contentResult = Invoke-RestMethod -Method GET -Headers $headerParams -Uri $listAvailableContentUri

            #Loop for each Content
            foreach($obj in $contentResult){
                #Retrieve Content
                $data = Invoke-RestMethod -Method GET -Headers $headerParams -Uri ($obj.contentUri)
                #Loop through each Record in the Content
                foreach($event in $data){
                    #Filtering for Record types
                    #Get all Record Types
                    if($recordTypes -eq "0"){
                        #MCASのアラートは除く
                        if(($event.Source) -ne "Cloud App Security"){
                            #Write each event to Log A
                            $writeResult = Write-OMSLogfile (Get-Date).ToUniversalTime() $customLogName $event $workspaceId $workspaceKey
                            #$writeResult
                        }
                    }
                    else{
                        #Get only certain record types
                        $types = ($recordTypes).split(",")
                        if(($event.RecordType) -in $types){
                            #MCASのアラートは除く
                            if(($event.Source) -ne "Cloud App Security"){
                                #write each event to Log A
                                $writeResult = Write-OMSLogfile (Get-Date).ToUniversalTime() $customLogName $event $workspaceId $workspaceKey
                            }
                        }
                        
                    }
                }
            }

    function Write-OMSLogfile {
        [cmdletbinding()]
            Param(
            [Parameter(Mandatory = $true, Position = 0)]
            [datetime]$dateTime,
            [parameter(Mandatory = $true, Position = 1)]
            [string]$type,
            [Parameter(Mandatory = $true, Position = 2)]
            [psobject]$logdata,
            [Parameter(Mandatory = $true, Position = 3)]
            [string]$CustomerID,
            [Parameter(Mandatory = $true, Position = 4)]
            [string]$SharedKey
        )
        Write-Verbose -Message "DateTime: $dateTime"
        Write-Verbose -Message ('DateTimeKind:' + $dateTime.kind)
        Write-Verbose -Message "Type: $type"
        write-Verbose -Message "LogData: $logdata"    

        function Build-signature ($CustomerID, $SharedKey, $Date, $ContentLength, $method, $ContentType, $resource) {
            $xheaders = 'x-ms-date:' + $Date
            $stringToHash = $method + "`n" + $contentLength + "`n" + $contentType + "`n" + $xHeaders + "`n" + $resource
            $bytesToHash = [text.Encoding]::UTF8.GetBytes($stringToHash)
            $keyBytes = [Convert]::FromBase64String($SharedKey)
            $sha256 = New-Object System.Security.Cryptography.HMACSHA256
            $sha256.key = $keyBytes
            $calculateHash = $sha256.ComputeHash($bytesToHash)
            $encodeHash = [convert]::ToBase64String($calculateHash)
            $authorization = 'SharedKey {0}:{1}' -f $CustomerID,$encodeHash
            return $authorization
        }

        # Function to create and post the request
        Function Post-LogAnalyticsData ($CustomerID, $SharedKey, $Body, $Type) {
            $method = "POST"
            $ContentType = 'application/json'
            $resource = '/api/logs'
            $rfc1123date = ($dateTime).ToString('r')
            $ContentLength = $Body.Length
            $signature = Build-signature `
                -customerId $CustomerID `
                -sharedKey $SharedKey `
                -date $rfc1123date `
                -contentLength $ContentLength `
                -method $method `
                -contentType $ContentType `
                -resource $resource
            $uri = "https://" + $customerId + ".ods.opinsights.azure.com" + $resource + "?api-version=2016-04-01"
            $headers = @{
                "Authorization" = $signature;
                "Log-Type" = $type;
                "x-ms-date" = $rfc1123date
                "time-generated-field" = $dateTime
            }
            $response = Invoke-WebRequest -Uri $uri -Method $method -ContentType $ContentType -Headers $headers -Body $body -UseBasicParsing
            Write-Host -message ('Post Function Return Code ' + $response.statuscode)
            return $response.statuscode
        }

        # Check if time is UTC, Convert to UTC if not.
        # $dateTime = (Get-Date)
        if ($dateTime.kind.tostring() -ne 'Utc'){
            $dateTime = $dateTime.ToUniversalTime()
            Write-Verbose -Message $dateTime
        }

        # Add DateTime to hashtable
        #$logdata.add("DateTime", $dateTime)
        $logdata | Add-Member -MemberType NoteProperty -Name "DateTime" -Value $dateTime

        #Build the JSON file
        $logMessage = ConvertTo-Json $logdata -Depth 20
        Write-Verbose -Message $logMessage

        #Submit the data
        $returnCode = Post-LogAnalyticsData -CustomerID $CustomerID -SharedKey $SharedKey -Body ([System.Text.Encoding]::UTF8.GetBytes($logMessage)) -Type $type
        Write-Verbose -Message "Post Statement Return Code $returnCode"
        return $returnCode
    }
            
            #Handles Pagination
            $nextPageResult = Invoke-WebRequest -Method GET -Headers $headerParams -Uri $listAvailableContentUri
            If(($nextPageResult.Headers.NextPageUrl) -ne $null){
                $nextPage = $true
                $listAvailableContentUri = $nextPageResult.Headers.NextPageUrl
            }
            Else{$nextPage = $false}
        } until ($nextPage -eq $false)

    }

クエリの実行結果

Log Analytics側でクエリを実行すると下記のようにデータを確認できます。Office365ManagementAPI_CLにデータが入っていることが分かります。

image.png

まとめ

Office 365 Management API と Data Collector API を PowerShell を用いて実行して、Office 365 の監査ログを Log Analytics (Azure Sentinel) に格納できることを確認しました。上記の手法を用いると、Audit.General や DLP.All など Sentinel のコネクターでは取得できないレコードタイプのログを Sentinel に格納できるようになります。

*本稿は、個人の見解に基づいた内容であり、所属する会社の公式見解ではありません。また、いかなる保証を与えるものでもありません。正式な情報は、各製品の販売元にご確認ください。

7
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
7