【Azure】App Serviceのアクセスログを自動かつ永続的に保存するTech TIPS

Azure App Serviceのアクセスログはデフォルトで永続的に保存されず、古いログから切り捨てられてしまう。場合によっては、古いログを確認しなければならないこともあるだろう。そこで、Azure Storage(ストレージアカウント)へ永続的にログを保存する方法を紹介する。

» 2024年04月03日 05時00分 公開
[島田広道デジタルアドバンテージ]
「Tech TIPS」のインデックス

連載目次

【Azure】App Servcieのログを永続的に保存

対象:Azure App Service、Azure Storage(ストレージアカウント)


App Serviceのログを捨てずにずっと保存しておきたい!

 公開Webサイトでは、セキュリティ上の事故などに備えるため、古いアクセスログでも捨てずに保存し続けなければならないことがある。また、顧客から「サイト評価のため、過去数年のアクセス数を提供してほしい」とお願いされることがあるかもしれない。

 しかし、Azure App ServiceによるWebサイトでは、診断ログなどは一定の容量を超えて保存できない。また、ログがApp Service内部に保存されるため、やや参照しにくいのと、App Serviceを作り直したときにうっかりログを削除してしまいそうだ。

 Azure MonitorのLog Analyticsにログを送信している場合でも、デフォルトの設定で参照可能なのは直近30日間のログに限られる。

 そこで本Tech TIPSでは、App Storage(以下、ストレージアカウント)を利用してApp Serviceのログを永続的に保存するための設定方法と注意点を紹介する。設定手段はAzureポータルまたはARMテンプレート(Bicep)とする。また保存先のストレージアカウントは、対象のApp Serviceと同じリージョンに作成済みとする。

■執筆時の各種ツール/APIのバージョン

  • Azure CLI: Ver. 2.58.0
  • Bicep CLI: Ver. 0.26.54
  • Bicepでのデプロイ時のAPIバージョン: 2022-09-01(App Service)、2021-05-01-preview(Azure Monitor)

【GUIポータル】App ServiceのログをStorageへ永続的に保存するには

 AzureポータルでApp Serviceのログがストレージアカウントへ保存されるようにするには、以下の画面のような手順で設定する。

AzureポータルでApp ServiceのログをStorageへ保存する設定(1/2) AzureポータルでApp ServiceのログをStorageへ保存する設定(1/2)
AzureポータルでApp ServiceのログをStorageへ保存する設定(2/2) AzureポータルでApp ServiceのログをStorageへ保存する設定(2/2)

■操作手順

  1. Azureポータルで[App Service]−[<対象のApp Service名>]を開く
  2. 左側メニューで「監視」欄の[診断設定]をクリック
  3. 右ペインで[診断設定を追加する]をクリック
  4. 診断設定」画面が表示されたら、[診断設定の名前]にこの診断設定の名称を記入する。ひも付けるリソース(App Service)や保存先(storage)が分かるような名前にすると識別しやすい
  5. 宛先の詳細]欄の[ストレージアカウントへのアーカイブ]チェックボックスにチェックを入れて「オン」にする
  6. 場所]欄の[サブスクリプション][ストレージアカウント]でストレージアカウントを選択
  7. ログ]欄の[カテゴリ]で、保存したいログのチェックボックスにチェックを入れて「オン」にする
  8. 左上にあるメニューの[保存]をクリックすると、設定内容が保存される
  9. 左上のパンくずリストの[<App Service名> | 診断設定]をクリックすると、元の画面に戻る

 App Serviceでは下表のように複数のログが記録される。

「カテゴリ」に表示されるログ名称 概要
Report Antivirus Audit Logs ウイルススキャンや、アップロードされたウイルス感染ファイルのログ
HTTP logs HTTPリクエストのログ(いわゆるアクセスログ)
App Service Console Logs サイトやコンテナからコンソール(標準出力や標準エラー出力)への出力ログ
App Service Application Logs アプリから出力されたログ
Site Content Change Audit Logs App Service内のコンテンツファイルの改変ログ
Access Audit Logs FTPなどでApp Serviceにログイン/サインインしたアカウントの監査ログ
IPSecurity Audit logs ネットワークのアクセス制限で許可/拒否された通信のログ
App Service Platform logs App Serviceの自動復旧などプラットフォーム提供の機能のログ
App Service Authentication logs App Serviceの認証ログ。執筆時点ではプレビュー
App Serviceで保存できるログの種類(2024年4月時点)
リンク先はMicrosoft Learnのレファレンスページ。

 アプリによっては、ほとんど記録されないログもある。必要なログだけチェックを入れて「オン」にして保存すればよい。

【Bicep】App ServiceのログをStorageへ永続的に保存するには

 以下に、ログをストレージアカウントへ保存する設定をしつつ、App ServiceをデプロイするためのARMテンプレートの例を紹介していく(やや長いので3つに分割している)。

 まず、保存するログを定義している部分を記す。

// 「診断設定」で保存するログ
var diagSettings = {
  logs: [ // 以下、コメントはポータルでの名称
    'AppServiceHTTPLogs' // HTTP logs
    'AppServiceConsoleLogs' // App Service Console Logs
    'AppServiceAppLogs' // App Service Application Logs
    'AppServiceAuditLogs' // Access Audit Logs
    'AppServiceIPSecAuditLogs' // IPSecurity Audit logs
    'AppServicePlatformLogs' // App Service Platform logs
    'AppServiceAntivirusScanAuditLogs' // Report Antivirus Audit Logs
    'AppServiceFileAuditLogs' // Site Content Change Audit Logs
    'AppServiceAuthenticationLogs' // App Service Authentication logs (preview)
  ]
}

【Bicep】App ServiceのARMテンプレート――「診断設定」の保存ログの指定
※Microsoftのレファレンス:AppServiceAntivirusScanAuditLogsAppServicePlatformLogs

 前述したように、App Serviceではアクセスログ(HTTP Logs)をはじめとして、複数のログが記録される。そのうち必要なログを選んで、配列「diagSettings」の「logs」キー以下に定義する。

 ただし、ここで指定すべきログの名称(以下、「ログ略称」)は、ポータルの「診断設定」の編集画面に表示される名称(「HTTP logs」など)とは異なるので注意が必要だ。例えば、ログ名称が「HTTP logs」の場合、対応するログ略称は「AppServiceHTTPLogs」となる。その他のログについては上記リストのコメントに記した。また各ログの属性や列については、上記リストのレファレンスのリンク先ページ(Microsoft Learn)を参照していただきたい。

 次は、既存リソースのStorage Account(ストレージアカウント)とApp Serviceプランを定義している部分だ。

// 既存リソース: ログ用ストレージアカウント
param logStorageRG string
param logStorageName string

resource logStgAccount 'Microsoft.Storage/storageAccounts@2023-01-01' existing = {
  name: logStorageName
  scope: resourceGroup(logStorageRG)
}

// 既存リソース: App Serviceプラン
param appServicePlanRG string
param appServicePlanName string

resource appServicePlan 'Microsoft.Web/serverfarms@2022-09-01' existing = {
  name: appServicePlanName
  scope: resourceGroup(appServicePlanRG)
}

【Bicep】App ServiceのARMテンプレート――既存リソースの定義
※Microsoftのレファレンス:Microsoft.Storage storageAccountsMicrosoft.Web/serverfarms

 最後は、新たなリソースを生成している部分である。診断設定は「拡張リソース」として生成する。

param location string = resourceGroup().location
param siteName string // App Serviceの名前

// リソース生成: App Serviceのサイト本体
resource webApp 'Microsoft.Web/sites@2022-09-01' = {
  name: siteName // App Service名
  location: location
  properties: {
    serverFarmId: appServicePlan.id // App ServiceプランのIDを指定
    // ……<省略>……
  }
}

// 拡張リソース生成: 診断設定
resource diagSetting 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = {
  name: 'diag-storage-${siteName}' // この診断設定の名前
  scope: webApp // ひも付けるApp Serviceのリソースを指定
  properties: {
    storageAccountId: logStgAccount.id // ログ用ストレージアカウントのIDを指定
    logs: [for log in diagSettings.logs: { // 保存するログをループで1つずつ指定
      category: log // ログ名称
      enabled: true
    }]
  }
}

【Bicep】App ServiceのARMテンプレート――新規リソースの生成
※Microsoftのレファレンス: Microsoft.Web sitesMicrosoft.Insights diagnosticSettings

 ポイントの一つは、ログを生成するリソース(ここではApp Service)と診断設定とのひも付けだ。具体的にはリソース「diagSetting」の「scope」に、ログ生成側のリソース(ここでは「webApp」)を指定する。

 もう一つ、ログを保存するストレージアカウントについては、同じくリソース「diagSetting」の「properties.storageAccountId」にそのIDを指定すること。

 保存するログは「properties.logs」に配列で列挙する。上記リストでは、変数「diagsettings」の「log」に記したログ略称をforループで1つずつ設定している。ちなみにメトリックを保存したいなら、「properties.metrics」の方に列挙する必要がある。

ストレージアカウントに保存されるログの場所や形式

 診断設定によるログは、選択したストレージアカウントの[Blob Containers]−[insight-logs-<ログ略称>]というコンテナに保存される。そのファイル名は「PT1H.json」で、1時間ごとに1ファイルずつ生成される。パスは、以下の画面と操作手順に記している(ストレージアカウントのブラウズには「Azure Storage Explorer」を用いた)。

診断設定によってストレージアカウントに保存されたログファイルを確認する 診断設定によってストレージアカウントに保存されたログファイルを確認する

■操作手順

  1. Azure Storage Explorerアプリを起動
  2. 左上の[エクスプローラー]ツリーで、ログ保存先のストレージアカウントを選択
  3. Blob Containers]−[insight-logs-<ログ略称>]を選択
  4. 右上ペインで以下のようにたどっていく:
    resourceId=
     SUBSCRIPTIONS
      <サブスクリプションID>
       RESOURCEGROUPS
        <リソースグループ名>
         PROVIDERS
          MICROSOFT.WEB
           SITES
            <App Service名>
             y=<年>
              m=<月>
               d=<日>
                h=<時>
                 m=00
    <月><日><時>は1桁だったら頭に「0(ゼロ)」を付けること。これでログファイル[PT1H.json]が表示されるはずだ

 診断設定では、複数のリソースからのログを単一のストレージアカウントに保存するように設定できる。その場合、上記のようにサブスクリプションID/リソースグループ名/リソース名がログファイルのパスに含まれるため、重複して上書きされる恐れはない。

 以下は、App ServiceのHTTP Logsが格納されたPT1H.jsonをVisual Studio Codeで開いたところだ。

診断設定によって保存されたログファイル「PT1H.json」をエディタで開いたところ 診断設定によって保存されたログファイル「PT1H.json」をエディタで開いたところ

 ログファイルの拡張子が「.json」なのでJSONだと思うだろう。しかし実際には、隣接するハッシュ同士がカンマで区切られておらず、厳密にはJSONの仕様から外れている。例えばRubyのJSON.loadでファイルまるごと読み出そうとすると、エラーが発生して失敗する。

 実態は、1行ごとにJSONフォーマットで書き出されたログというべきだろう。分析する際は、1行ずつJSONからハッシュに変換するとよい。

{
    "time": "2024-04-01T01:02:44.9702090Z",
    "EventTime": "2024-04-01T01:02:44.9702090Z",
    "resourceId": "/SUBSCRIPTIONS/*/RESOURCEGROUPS/RG-FWIN2K240403-DEV-JW-001/PROVIDERS/MICROSOFT.WEB/SITES/APP-FWIN2K240403-DEV-JW-001",
    "properties": "{\"CsHost\":\"app-fwin2k240403-dev-jw-001.azurewebsites.net\",\"CIp\":\"127.0.0.1\",\"SPort\":\"80\",\"CsUriStem\":\"\\/\",\"CsUriQuery\":\"\",\"CsMethod\":\"GET\",\"TimeTaken\":8,\"ScStatus\":\"200\",\"Result\":\"Success\",\"CsBytes\":\"739\",\"ScBytes\":\"4753\",\"UserAgent\":\"AlwaysOn\",\"Cookie\":\"ARRAffinity: *; \",\"CsUsername\":\"\",\"Referer\":\"\",\"ComputerName\":\"*\",\"Protocol\":\"HTTP\\/1.1\"}",
    "category": "AppServiceHTTPLogs",
    "EventStampType": "Stamp",
    "EventPrimaryStampName": "*",
    "EventStampName": "*",
    "Host": "*",
    "EventIpAddress": "10.*.*.33"
}
{
    "time": "2024-04-01T01:02:44.9702090Z",
    "以下": "省略"
}

診断設定によって保存されたアクセスログ(体裁変更済み)

 App Serviceの種別(WindowsインスタンスかLinuxインスタンスか、など)によっては、キーや値が異なることがある。また上のリストでは、「properties」がJSONの文字列で表されている一方で、別のログでは素直にハッシュの入れ子で表されている場合もある。このように、インスタンスやログの種類などによってログファイルの構成が微妙に異なることがあるので注意しよう。

【注意】保存ログが増大するとストレージアカウントの料金が増えていく

 ここまで「永続的に」ログを保存するための設定について説明してきた。しかし、ログを消すことなく保持し続けていると、溜め込んだ容量の分だけストレージアカウントの料金も増えてしまう。現実的には、料金増大はいずれ無視できなくなるだろう。

 料金を抑える方法としては、古いログを切り捨てることが挙げられる。それには、ストレージアカウントで「ライフサイクル管理ポリシー」を設定するとよい。

 この機能を利用すると、例えば最終更新から1年≒365日を過ぎたら自動的にログを削除する、といったことが可能だ。また「クール」「コールド」「アーカイブ」という、より安いアクセス層への移動も自動化できる。

 詳細は、Microsoft Learnの「データ ライフサイクルを自動管理してコストを最適化するが詳しいので、参照していただきたい。

 ライフサイクル管理ポリシーを設定しつつ、削除直前にAzureの外側の安価なストレージ(ローカルのNASなど)へログを移す、といったことも自動化できるだろう。ただし、ストレージアカウントからログを読み出す(データを転送する)際にも料金は別途かかる点は留意しておきたい。

●診断設定の保持期間設定機能(retentionPolicy)は廃止予定なので使わない

 診断設定(Microsoft.Insights diagnosticSettings)のARMテンプレートのレファレンスには、「retentionPolicy」という設定項目がある。以前は、これを利用すると診断設定内でログの保持期間を有限に設定できた。またAzureポータルでも同じ設定が可能だった。

 しかし、この機能は執筆時点で既に設定できなくなっており、2025年9月末には完全に廃止される予定だ。今後は、前述したストレージアカウントのライフサイクル管理ポリシーを利用する必要がある。詳細は、本稿末尾の「■関連リンク」欄にあるMicrosoftサイトの解説ページを参照していただきたい。

「Tech TIPS」のインデックス

Tech TIPS

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。