Grafana 發送異常通知(監控 WAF 異常流量)

前言

在前幾篇文章中,我記錄了 如何安裝 Grafana 以及 將事件器的 Log 整合至 Grafana 進行集中管理,當然除了日誌,如果希望監控其它指標,比如伺服器效能,也都可以統一傳送至 Grafana 方便進行管理,但這些我就不再一一介紹了。

另外當系統出現異常時,提供即時通知是非常重要的功能,本文將分享如何在 Grafana 中設定異常通知功能,Grafana 支援多種異常通知方式,包括 LINE、郵件、API、Teams 等,這裡會分享我自己使用的兩種方式:【LINE 通知】和【呼叫外部 API】。

接下來,我將詳細說明這兩種通知方式的設定步驟。


設定通知渠道 Alerting → Contact points

  • 設定 LINE 通知
    • Name:輸入通知類型的識別名稱。
    • Integration:選擇 LINE。
    • Token:要通知的 LINE 群組 Token,請先到 LINE Notify 取得。
    • Optional LINE Settings (非必要)
      • Title:要在 LINE 通知顯示的標題(可使用樣板)。
      • Description:要在 LINE 通知顯示的內容(可使用樣板)。
    • Notification settings
      • Disable resolved message:這個項目關閉。
  • 設定 API 通知
    • Name:輸入通知類型的識別名稱。
    • Integration:選擇 Webhook。
    • URL:發生事件要呼叫的 API 網址。
    • Optional Webhook Settings (非必要)
      • Http Method:選擇 POST 或 PUT。
      • Authorization Header - Scheme:你的授權(自定義)。
  • 若指定使用 API ,當觸發異常通知事件時,收到的請求格式如下參考。
    {
        "receiver": "API",
        "status": "firing",
        "alerts": [
            {
                "status": "firing",
                "labels": {
                    "LINEGroup": "Standard",
                    "LINEGroup2": "Standard",
                    "alertname": "DatasourceError",
                    "datasource_uid": "b5219f7d-83bc-4971-90cb-768998609e3b",
                    "grafana_folder": "Alert-WAF",
                    "ref_id": "A",
                    "rulename": "每 10 鐘超過 50 次攻擊"
                },
                "annotations": {
                    "description": "測試站台違反 WAF 規則超過指定上限,請協助確認",
                    "summary": "==== 詳細違反規則說明如下 ====\n   WAF : [no value]\n   次數 : [no value]"
                },
                "startsAt": "2023-12-12T17:30:10+08:00",
                "endsAt": "0001-01-01T00:00:00Z",
                "generatorURL": "http://pex-test.primeeagle.net:3333/alerting/grafana/e6e62239-f924-4ccf-bc6a-be9b14622ae8/view?orgId=1",
                "fingerprint": "2aa447ec40d366b6",
                "silenceURL": "http://pex-test.primeeagle.net:3333/alerting/silence/new?alertmanager=grafana\u0026matcher=LINEGroup2%3DStandard\u0026matcher=LINEGroup%3DStandard\u0026matcher=alertname%3DDatasourceError\u0026matcher=datasource_uid%3Db5219f7d-83bc-4971-90cb-768998609e3b\u0026matcher=grafana_folder%3DAlert-WAF\u0026matcher=ref_id%3DA\u0026matcher=rulename%3D%E6%AF%8F+10+%E9%90%98%E8%B6%85%E9%81%8E+50+%E6%AC%A1%E6%94%BB%E6%93%8A\u0026orgId=1",
                "dashboardURL": "",
                "panelURL": "",
                "values": null,
                "valueString": ""
            }
        ],
        "groupLabels": {
            "alertname": "DatasourceError",
            "grafana_folder": "Alert-WAF"
        },
        "commonLabels": {
            "LINEGroup": "Standard",
            "LINEGroup2": "Standard",
            "alertname": "DatasourceError",
            "datasource_uid": "b5219f7d-83bc-4971-90cb-768998609e3b",
            "grafana_folder": "Alert-WAF",
            "ref_id": "A",
            "rulename": "每 10 鐘超過 50 次攻擊"
        },
        "commonAnnotations": {
            "description": "測試站台違反 WAF 規則超過指定上限,請協助確認",
            "summary": "==== 詳細違反規則說明如下 ====\n   WAF : [no value]\n   次數 : [no value]"
        },
        "externalURL": "http://pex-test.primeeagle.net:3333/",
        "version": "1",
        "groupKey": "{}/{LINEGroup=\"Standard\"}:{alertname=\"DatasourceError\", grafana_folder=\"Alert-WAF\"}",
        "truncatedAlerts": 0,
        "orgId": 1,
        "title": "[FIRING:1] DatasourceError Alert-WAF (Standard Standard b5219f7d-83bc-4971-90cb-768998609e3b A 每 10 鐘超過 50 次攻擊)",
        "state": "alerting",
        "message": "**Firing**\n\nValue: [no value]\nLabels:\n - alertname = DatasourceError\n - LINEGroup = Standard\n - LINEGroup2 = Standard\n - datasource_uid = b5219f7d-83bc-4971-90cb-768998609e3b\n - grafana_folder = Alert-WAF\n - ref_id = A\n - rulename = 每 10 鐘超過 50 次攻擊\nAnnotations:\n - description = 測試站台違反 WAF 規則超過指定上限,請協助確認\n - summary = ==== 詳細違反規則說明如下 ====\n   WAF : [no value]\n   次數 : [no value]\nSource: http://pex-test.primeeagle.net:3333/alerting/grafana/e6e62239-f924-4ccf-bc6a-be9b14622ae8/view?orgId=1\nSilence: http://pex-test.primeeagle.net:3333/alerting/silence/new?alertmanager=grafana\u0026matcher=LINEGroup2%3DStandard\u0026matcher=LINEGroup%3DStandard\u0026matcher=alertname%3DDatasourceError\u0026matcher=datasource_uid%3Db5219f7d-83bc-4971-90cb-768998609e3b\u0026matcher=grafana_folder%3DAlert-WAF\u0026matcher=ref_id%3DA\u0026matcher=rulename%3D%E6%AF%8F+10+%E9%90%98%E8%B6%85%E9%81%8E+50+%E6%AC%A1%E6%94%BB%E6%93%8A\u0026orgId=1\n"
    }
  • 本文使用 NetCore 來接收 Webhook 的請求,參考範例程式如下。
    [ApiController]
    [Route("api/[controller]")]
    public class TestController : ControllerBase
    { 
        // 使用 HttpPost 取得 FormBody Model
        [HttpPost]
        public IActionResult Post([FromBody] System.Text.Json.JsonElement model)
        {
            var json = model.ToString();
    
            // 按照日期 yyyyMMddHHmmss 將檔案存到本機 Log 資料夾,若資料夾不存在請先建立
            var fileName = DateTime.Now.ToString("yyyyMMddHHmmss");
            if (Directory.Exists("Log") == false) Directory.CreateDirectory("Log");
            System.IO.File.WriteAllText($"Log/{fileName}.json", json);
    
            return Ok(json);
        }
    }


通知樣板 Alerting → Contact points

非必要,若有需要自定義通知格式,包含標題、內容等等,皆可在 Alerting → Contact points → Notification templates 定義樣板內容,底下是本文設定的範例,我有使用到【AlertName】、【Description】、【Summary】,顯示的區域可以在本文末的參考畫面查看。

{{ define "WAFStandardTemplate" }}{{range .Alerts}}通知類型 : {{.Labels.alertname}}
{{.Annotations.description}}
{{if gt (len .Annotations.summary) 0}}{{.Annotations.summary}}{{end}}
{{end}}
{{end}}


通知規則 Alerting -> Alert rules

  1. 輸入要通知的規則名稱 (Enter alert rule name),請注意這邊只是設定收集規則,並不會真的發送通知,若要發送通知請完成此處設定後,繼續往下進行通知政策的設定。
  2. 定義查詢和警報條件 (Define query and alert condition),共分成 A、B、C 三個區域,各區域說明如下。
    • A:找出通知資料的條件,例如收集近 10 分鐘,攻擊數量的加總。
      • 設定收集資料區間,我選的是最近十分鐘。
      • 設定查詢數量,根據實際要篩選的條件進行設定。
      • 數量彙總,目的是為了將篩選出來的資料列轉換成下一步要通知的格式。
    • B:通知條件前處理,主要的目的與步驟 C 比較的資料前處理,以下圖為例,會將條件 A 查詢結果的數量進行加總,若查詢結果包含非數值的資料列,會將該筆設定為 0。
    • C:閾值,要通知的條件值,例如,超過 10 次就通知,另外請注意,這裡是通知條件,所以設定完成後記得點選右上角的設定。
    • 都完成上述的設定,可以使用底下的 preview 功能確認是否有滿足通知條件。
  3. 設定評估行為 (Set evaluation behavior)。
    • Folder:通知規則的資料夾,這邊依照自己的需求分類即可,ex. Alert Evaluation。
    • Evaluation group:同一個評估群組多久收集一次資料,當滿足這個時間條件時,僅會將狀態改成 padding,並不會真的發送 (仍需考量 Padding 和通知政策內的設定) ,但我個人是在這邊設定真正要發送的時間。
    • Pending period:這裡指的當符合收集條件後,必須持續維持多久的時間才會滿足發送條件,也就是 firing。
    • Alert state if no data or all values are null:若沒有定期通知的需求,沒資料請將此處設定改成 OK,否則會按照通知政策設定的時間間隔,定期的發送通知(包含正常狀態)。
  4. 新增註釋 (Add annotations):非必要,發送通知需要附加的訊息,依實際需求設定即可。
  5. 通知配置(Configure notifications):當滿足條件時會夾帶的標籤設定,可透過此處與通知政策結合,達到指定發送群組的需求,完成設定後可點選 Preview routing 來確認是否有匹配到通知群組。


通知政策 Alerting -> Notification policies 

請注意這邊非常重要,不注意設定你會查問題查很久,預警規則 (Alert rules) 的設定只是收集資料而已,實際發送是還是會跟這邊的設定值有關係,並且此處的設定會牽扯到是否間隔多久才會通知,但預設值其實蠻久的,若不調整預設值,會造成你的發送區間若還在預設值內,則不會重新發送,各欄位設定如下說明。

  • Matching labels:搭配 Alert rules 內的設定,便可以達到指定通知群組的效果
  • Contact point:要通知的渠道,這邊可選擇一開始的設定。
  • Continue matching subsequent sibling nodes:若同一個警告有符合多個通知 Label,則必須開啟此欄位,否則通知完第一個政策後就會停止了。
  • Override general timings
    • Group wait:為傳入警報建立的新群組發送初始通知之前的等待時間。如果為空,將從父策略繼承。
    • Group interval:發送第一個通知後,為該群組發送一批新警報的等待時間。如果為空,將從父策略繼承,多個通知會套用此設定
    • Repeat interval:成功發送警報後重新發送警報的等待時間,建議與 Alert rules 內的 Evaluation group 時間設定一樣或者多一分鐘(避免重複發送)這個最重要了,有點雷,預設是 4 個小時,卡在這邊超久,而且搭配警告設定那邊,若不把無資料的設定關閉,會每隔四個小時自動發出一個沒有數值的通知

通知參考畫面

LINE 收到的通知



參考網站 

留言