📈

Office 365 管理 API を使って SharePoint Online の監査ログを取得する

2022/01/01に公開

はじめに

いままでずっと SharePoint Online の監査ログの生データは取得できないと思っていたのですが、実は Office 365 管理 API というものを使えば取得できるのだそうです。Office 365 管理 API は SharePoint、Exchange、Teams、Power Platform などのさまざまな監査ログを取得できるのですが、特に利用状況の監視目的で SharePoint Online の監査ログを取りたいという要望は非常に多いため、この方法を使えば解決できるのはないかと思います。

なお今回は以下の記事を参考にしています。

https://qiita.com/YoshiakiOi/items/16866f40c29618f05f39

サンプル コード

https://github.com/karamem0/samples/tree/main/sharepoint-office-365-management-api

実行手順

Office 365 管理 API でログを取得するには以下の手順が必要になります。

  • アクセス トークンを取得する
  • サブスクリプションを作成する
  • コンテンツの URL を取得する
  • コンテンツを取得する

アクセス トークンを取得する

Office 365 管理 API を使用するためには、はじめに Azure AD にアプリを登録する必要があります。API のアクセス許可 では Office 365 Management APIs - アプリケーションのアクセス許可 - ActivityFeed.Read を追加します。

またアプリケーション シークレットも取得しておきます。

Office 365 管理 API は Azure AD の v2.0 エンドポイントに対応していないので MSAL を使うことができません。ADAL を使ってもいいのですが、面倒なので、今回は直接 HttpClient で取りに行くようにします。といっても Client Credentials Grant なのでそれほど難しくはありません。

private static void AcquireToken()
{
    var httpRequestUrl = $"https://login.microsoftonline.com/{TenantId}/oauth2/token";
    var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, httpRequestUrl);
    var httpRequestContent = new FormUrlEncodedContent(new Dictionary<string, string>()
    {
        { "grant_type", "client_credentials" },
        { "resource", Resource },
        { "client_id", ClientId },
        { "client_secret", ClientSecret }
    });
    httpRequestMessage.Content = httpRequestContent;
    var httpResponseMessage = HttpClient.SendAsync(httpRequestMessage).GetAwaiter().GetResult();
    var httpResponseContent = httpResponseMessage.Content.ReadAsStringAsync().GetAwaiter().GetResult();
    var httpResponseJson = JsonConvert.DeserializeObject<JToken>(httpResponseContent);
    AccessToken = httpResponseJson.Value<string>("access_token");
}

サブスクリプションを作成する

Office 365 管理 API のコンテンツ タイプ (Audit.SharePoint) に対してサブスクリプションを作成します。Webhook も登録できるようなのですが、今回は省略します。PublisherIdentifier は任意の GUID を指定してください。

private static void CreateSubscription()
{
    var httpRequestUrl = $"https://manage.office.com/api/v1.0/{TenantId}/activity/feed/subscriptions/start" +
      $"?contentType=Audit.SharePoint" + 
      $"&PublisherIdentifier={PublisherIdentifier}";
    var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, httpRequestUrl);
    httpRequestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken);
    var httpResponseMessage = HttpClient.SendAsync(httpRequestMessage).GetAwaiter().GetResult();
    var httpResponseContent = httpResponseMessage.Content.ReadAsStringAsync().GetAwaiter().GetResult();
}

コンテンツの URL を取得する

ログを取得する時間を指定してコンテンツ データのダウンロード先の URL を取得します。時間は 24 時間以内で過去 7 日以内である必要があります。今回は 1 日前のデータを取得するように指定します。

private static void GetContentUri()
{
    var startTime = DateTime.Today.AddDays(-1).ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:ss");
    var endTime = DateTime.Today.AddSeconds(-1).ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:ss");
    var httpRequestUrl = $"https://manage.office.com/api/v1.0/{TenantId}/activity/feed/subscriptions/content" +
        $"?contentType=Audit.SharePoint" +
        $"&PublisherIdentifier={PublisherIdentifier}" +
        $"&startTime={startTime}" +
        $"&endTime={endTime}";
    var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, httpRequestUrl);
    httpRequestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken);
    var httpResponseMessage = HttpClient.SendAsync(httpRequestMessage).GetAwaiter().GetResult();
    var httpResponseContent = httpResponseMessage.Content.ReadAsStringAsync().GetAwaiter().GetResult();
    var httpResponseJson = JsonConvert.DeserializeObject<JArray>(httpResponseContent);
    ContentUri = httpResponseJson[0].Value<string>("contentUri");
}

コンテンツを取得する

取得した URL から JSON 形式のコンテンツを取得します。

private static void GetContents()
{
    var httpRequestUrl = ContentUri;
    var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, httpRequestUrl);
    httpRequestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken);
    var httpResponseMessage = HttpClient.SendAsync(httpRequestMessage).GetAwaiter().GetResult();
    var httpResponseContent = httpResponseMessage.Content.ReadAsStringAsync().GetAwaiter().GetResult();
    var httpResponseJson = JsonConvert.DeserializeObject<JArray>(httpResponseContent);
    Console.WriteLine(JsonConvert.SerializeObject(httpResponseJson, Formatting.Indented));
}

実行結果

以下のような JSON が出力されます。サンプルはファイルのダウンロードですが、それだけではなく、いろいろな種類のログが取得できます。

[
  {
    "CreationTime": "2020-09-01T14:00:03",
    "Id": "bea6430c...",
    "Operation": "FileDownloaded",
    "OrganizationId": "92dbed3f...",
    "RecordType": 6,
    "UserKey": "i:0h.f|membership|{{user-principal-name}}",
    "UserType": 0,
    "Version": 1,
    "Workload": "OneDrive",
    "ClientIP": "203.0.113.1",
    "ObjectId": "https://{{tenant-name}}-my.sharepoint.com/personal/{{user-principal-name}}/Documents/fitbit.json",
    "UserId": "{{user-principal-name}}",
    "CorrelationId": "1aba0151...",
    "EventSource": "SharePoint",
    "ItemType": "File",
    "ListId": "ccf377fa...",
    "ListItemUniqueId": "3afd549b...",
    "Site": "0815189e...",
    "WebId": "15cdf073...",
    "HighPriorityMediaProcessing": false,
    "SourceFileExtension": "json",
    "SiteUrl": "https://{{tenant-name}}-my.sharepoint.com/personal/{{user-principal-name}}/",
    "SourceFileName": "fitbit.json",
    "SourceRelativeUrl": "Documents"
  },
...
]

何が取得できるかについては以下が参考になります。

https://docs.microsoft.com/ja-jp/microsoft-365/compliance/search-the-audit-log-in-security-and-compliance?WT.mc_id=M365-MVP-5002941

おわりに

Office 365 管理 API に関する情報は以下にまとまっています。

https://docs.microsoft.com/ja-jp/office/office-365-management-api?WT.mc_id=M365-MVP-5002941

オンプレの SharePoint で監査ログを取っていろいろやっていたことを、SharePoint Online に移行しても同じことをやりたい、というときにぜひ使っていただきたいと思います。

Discussion