いままでずっと SharePoint Online の監査ログの生データは取得できないと思っていたのですが、実は Office 365 管理 API というものを使えば取得できるのだそうです。Office 365 管理 API は SharePoint、Exchange、Teams、Power Platform などのさまざまな監査ログを取得できるのですが、特に利用状況の監視目的で SharePoint Online の監査ログを取りたいという要望は非常に多いため、この方法を使えば解決できるのはないかと思います。
なお今回は以下の記事を参考にしています。
サンプル コード
実行手順
Office 365 管理 API でログを取得するには以下の手順が必要になります。
- アクセス トークンを取得する
- サブスクリプションを作成する
- コンテンツの URL を取得する
- コンテンツを取得する
アクセス トークンを取得する
Office 365 管理 API を使用するためには、はじめに Azure Active Directory にアプリを登録する必要があります。[API のアクセス許可] では [Office 365 Management APIs] - [アプリケーションのアクセス許可] - [ActivityFeed.Read] を追加します。
またアプリケーション シークレットも取得しておきます。
Office 365 管理 API は Azure Active Directory の 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-9db6-400c-ebbf-08d84e7f532c", "Operation": "FileDownloaded", "OrganizationId": "92dbed3f-d37a-4f19-a392-f6970505cc6a", "RecordType": 6, "UserKey": "i:0h.f|membership|10033fffac7f4b34@live.com", "UserType": 0, "Version": 1, "Workload": "OneDrive", "ClientIP": "52.185.144.178", "ObjectId": "https://karamem0jp-my.sharepoint.com/personal/takashi_shinohara_karamem0_jp/Documents/fitbit.json", "UserId": "takashi.shinohara@karamem0.jp", "CorrelationId": "1aba0151-abda-4b69-a102-a9319a2a9e15", "EventSource": "SharePoint", "ItemType": "File", "ListId": "ccf377fa-0605-41b5-925a-224e62839884", "ListItemUniqueId": "3afd549b-4c58-4026-a7e2-d4fcc1a2ebe0", "Site": "0815189e-2f76-44f2-89fe-f2dd7260e20d", "WebId": "15cdf073-9e78-4667-94ea-96abe6aa860f", "HighPriorityMediaProcessing": false, "SourceFileExtension": "json", "SiteUrl": "https://karamem0jp-my.sharepoint.com/personal/takashi_shinohara_karamem0_jp/", "SourceFileName": "fitbit.json", "SourceRelativeUrl": "Documents" }, ... ]
何が取得できるかについては以下が参考になります。
まとめ
Office 365 管理 API に関する情報は以下にまとまっています。
オンプレの SharePoint で監査ログを取っていろいろやっていたことを、SharePoint Online に移行しても同じことをやりたい、というときにぜひ使っていただきたいと思います。