iT邦幫忙

2026 iThome 鐵人賽

DAY 24
0
自我挑戰組

一鍵完成六套開源防禦系統整合系列 第 24 篇

Grafana:線接好了,畫面要自己畫

  • 分享至 

  • xImage
  •  

防禦節點(主機 B)上除了 WAF,還裝了幾個別人寫的系統。這一系列每篇只談一個,不深入它的設定細節,只回答三件事:它是什麼、它在主機 A 與主機 B 之間佔哪一段、少了它整體會缺什麼。本篇是 Grafana。

先講結論。Grafana 是把查詢結果畫成圖表的網頁工具。安裝包替它做了三件事:建好管理員帳號、裝好 ClickHouse 的外掛、設好通往 ClickHouse 的連線。沒有做的是畫面:登入之後一個儀表板都沒有,要看什麼得自己建。它只讀 ClickHouse,自己不存事件,不參與偵測、建案、處置的任何一段,主機 A 也不經過它。停掉它,除了看不到圖,什麼都不受影響。它補上的是 ClickHouse 那一篇留下的缺口:同樣的 SQL,不必每次重打,結果會自己更新,時間也換成你所在的時區。

一、它是什麼

Grafana 是 Grafana Labs 公司維護的開源儀表板工具,授權 AGPLv3。它自己不收集資料,而是接上別的資料庫,把查詢結果畫成折線、長條、表格,排成一頁一頁的儀表板(dashboard),頁面上的每一格叫面板(panel)。本安裝包用的容器映像是 grafana/grafana:11.3.0,是官方未修改的版本;另外裝了一個外掛 grafana-clickhouse-datasource,讓它看得懂 ClickHouse。

它在本安裝包裡的樣子:

項目 內容
是否安裝 預設會裝。安裝時加 --no-ui 就不裝,EveBox 與 Portainer 也一起不裝
網址 http://192.168.0.112:3000/,HTTP
誰能連 由主機 B 的防火牆限制來源:安裝時 --admin-ips 列出的位址與主機 A。其他來源連線逾時
帳號 admin 一個。密碼在安裝時隨機產生,印在安裝結尾,也存在主機 B 的 .env(GRAFANA_ADMIN_PASSWORD)。不開放匿名瀏覽,也不開放自行註冊
資料來源 一個,名稱 ClickHouse-secstack,指向同一台主機上的 ClickHouse、資料庫 secstack
儀表板 沒有
它自己的資料 帳號、儀表板、設定存在它自己的一個小資料庫裡,放在名為 grafana-data 的資料卷。這裡面沒有事件
資源 實測一台節點閒置時約佔 130 MB 記憶體

二、它接在哪裡

https://ithelp.ithome.com.tw/upload/images/20261008/20184261eqEUsxaT2g.png

圖上有三件事要看。

  • 它在整條事件路徑的旁邊,不在路徑上。事件由 Vector 寫進 ClickHouse,同時送往主機 A;這兩條路都不經過 Grafana。Grafana 只在有人開著儀表板的時候向 ClickHouse 發出查詢,沒人看就沒有查詢。
  • 它有兩份自己的東西,放在不同地方。帳號與在畫面上建的儀表板,存在它自己的資料庫裡;通往 ClickHouse 的連線設定,則是安裝包放在設定目錄裡的檔案,每次啟動時讀進來。這個差別在第五節會用到。
  • 主機 A 完全沒有接上它。主機 A 上的案件、簽核、封鎖決策都不在 Grafana 看得到的範圍內。它能畫的,只有 ClickHouse 裡的那兩張表。

三、登入之後看到什麼

在 --admin-ips 列出的電腦上開 http://192.168.0.112:3000/,帳號 admin,密碼取自主機 B:

# 主機 B
sudo grep '^GRAFANA_ADMIN_PASSWORD=' /opt/integrated-waf/.env

登入後是一個空的首頁。介面是英文的,以下的選單與按鈕名稱照畫面上的原文寫。左上角的選單裡,與本篇有關的是三項:

選單 出廠的內容 用途
Dashboards 空的 儀表板的清單。第四節建的東西會出現在這裡
Explore 可以直接用 臨時下一個查詢、看一次結果,不存檔。確認連線通不通,用它最快
Connections → Data sources 一筆 ClickHouse-secstack 通往 ClickHouse 的連線。不必改

先確認線是通的。進 Explore,上方的 Editor Type 預設是 Query Builder,把它切到 SQL Editor,貼上搭配元件篇 3 第五節的第一個查詢,按 Run Query:

SELECT source_system, count() AS n, max(event_time) AS latest
FROM events
WHERE event_time > now() - INTERVAL 1 DAY
GROUP BY source_system
ORDER BY n DESC
source_system  n   latest
suricata       12  2026-10-06 21:57:07
coraza         11  2026-10-06 21:58:13

數字和在 ClickHouse 直接查到的一樣,時間不一樣。ClickHouse 存的是 UTC,同一筆在那邊顯示 13:58:13;Grafana 依瀏覽器所在的時區換算,在台灣看到的是 21:58:13。上一篇提醒過「時間要自己加 8 小時」,在 Grafana 裡不必。

Query Builder 是用下拉選單組查詢的模式。它的資料表清單裡除了 events 與 events_per_minute,還有一個 .inner_id. 開頭的名字,那是每分鐘彙總實際存放資料的地方,不要選它。本篇一律用 SQL Editor。

四、做第一個面板

目標是一張圖:每個來源在每段時間各有幾筆事件。資料取自每分鐘彙總表 events_per_minute,它就是為這種圖準備的。

  1. 畫面右上角按 New,選 New dashboard,再按 Add visualization。
  2. 跳出資料來源的清單,選 ClickHouse-secstack。
  3. 下半部是查詢編輯區。Editor Type 切到 SQL Editor,Query Type 選 Time Series。
  4. 貼上下面的查詢,按 Run Query,上半部就會出現圖。
  5. 右側最上方可以換圖的種類,預設是 Time series。在 Panel options 的 Title 填上面板名稱。
  6. 按右上角的 Save dashboard,替儀表板取名後存檔。
SELECT $__timeInterval(minute) AS time, source_system, sum(events) AS n
FROM events_per_minute
WHERE $__timeFilter(minute)
GROUP BY time, source_system
ORDER BY time

這個查詢和上一篇的寫法只差兩個 $__ 開頭的字,它們是外掛提供的巨集,送出之前會被換成真正的 SQL:

巨集 送到 ClickHouse 時變成 作用
$__timeFilter(minute) minute >= toDateTime(…) AND minute <= toDateTime(…) 套用畫面右上角選的時間範圍。改選「過去 7 天」,查詢條件跟著變,不必改 SQL
$__timeInterval(minute) toStartOfInterval(toDateTime(minute), INTERVAL 60 second) 把時間切成一段一段。每段多長由 Grafana 依時間範圍與面板寬度決定,範圍拉長,每一段就變寬,圖上的點不會多到畫不下

Query Type 選 Time Series 時,外掛對查詢結果有兩個要求:第一欄是時間,其餘是數字;多出來的文字欄(這裡是 source_system)會被拿來把資料拆成幾條線,一個來源一條。事件少的節點,圖上會是零星的幾個點;在右側的 Graph styles 把 Style 改成 Bars,比折線好讀。

同一個儀表板可以繼續加面板(Add → Visualization)。下面三個查詢的 Query Type 都選 Table,圖的種類也選 Table,實測都跑得出結果。

各來源的筆數與最後出現的時間。high 是嚴重度最高一級的筆數。

SELECT source_system, count() AS n, countIf(severity_id >= 4) AS high, max(event_time) AS latest
FROM events
WHERE $__timeFilter(event_time)
GROUP BY source_system
ORDER BY n DESC

攻擊者位址前 10 名。位址欄是 IPv6 型態,這裡把 IPv4 位址前面的 ::ffff: 去掉。

SELECT replaceRegexpOne(toString(actor_ip), '^::ffff:', '') AS ip,
       count() AS n, uniqExact(source_system) AS sources, max(event_time) AS latest
FROM events
WHERE $__timeFilter(event_time)
GROUP BY actor_ip
ORDER BY n DESC
LIMIT 10

最新 20 筆。

SELECT event_time, source_system, severity_id,
       replaceRegexpOne(toString(actor_ip), '^::ffff:', '') AS ip, target_host, finding_title
FROM events
WHERE $__timeFilter(event_time)
ORDER BY event_time DESC
LIMIT 20

這些面板畫的是搭配元件篇 3 所說的全量,也繼承了它的範圍:只有命中規則的才在裡面,WAF 事件只記排第一的那條規則,內網打內網的也算。所以「攻擊者位址前 10 名」裡出現主機 B 自己或管理者的電腦是正常的,那是自己做的測試與主機 B 往外的連線。儀表板右上角可以設定自動重新整理的間隔;一筆事件從發生到圖上看得到,最短是管線本身的 5 秒。

五、畫好的東西存在哪裡

在畫面上建的儀表板,存在 Grafana 自己的資料庫裡,也就是 grafana-data 這個資料卷。它跟著資料卷走:

動作 儀表板
重啟容器、--update、--reconfigure 還在。實測停止再啟動,儀表板與資料來源都在
--uninstall(不加 --purge) 還在。資料卷與安裝目錄都保留,再裝一次就接回去
--uninstall --purge、把安裝目錄刪掉之後重裝、整台主機重灌 沒了。安裝腳本找不到原本的 .env 時,會把殘留的資料卷清掉再裝

想讓它不跟著資料卷消失,就把它變成檔案。在儀表板上按 Share,切到 Export 分頁,按 Save to file,會下載一個 JSON 檔。把它放進主機 B 的設定目錄:

# 主機 B
sudo cp 下載的檔案.json /opt/integrated-waf/grafana/provisioning/dashboards/

Grafana 每 30 秒看一次這個目錄,不必重啟。實測放進去之後 30 秒內載入。這個目錄不會被 --update 清掉,全新的 Grafana 啟動時也會讀它,所以資料卷沒了,儀表板還在。放進去之後有兩件事和原本不同,都實測過:

  • 檔案取代了資料庫裡的那一份。畫面上原本那個儀表板不會變成兩個,而是改由檔案接管,內容以檔案為準。
  • 刪掉檔案,儀表板就跟著消失。把檔案從目錄移走,30 秒內儀表板就從 Grafana 裡被移除。之後要改內容,改完重新匯出、覆蓋這個檔案;要搬到另一台節點,複製這個檔案過去。

六、它不做的事

限制 說明
出廠沒有畫面 沒有儀表板,沒有警示規則。安裝完成時,它能做的只有 Explore 裡的臨時查詢
不存事件 每一張圖都是當下向 ClickHouse 查出來的。ClickHouse 停了,面板就是錯誤訊息;超過 90 天、已經被 ClickHouse 刪除的資料,在這裡也查不到
看不到 ClickHouse 以外的東西 主機 A 上的案件與封鎖決策、Suricata 的連線記錄、WAF 的原始記錄都不在裡面。要把它們畫進來,得自己再接資料來源
不是唯讀的 它連 ClickHouse 用的是 secstack,就是那個能讀、能寫、能刪表的帳號。實測在 Grafana 的查詢編輯區送出建表與刪表的指令,都會執行。能登入 Grafana 的人,拿到的是 ClickHouse 的管理權,不只是看圖的權限
只有一個共用帳號 出廠只有 admin。要分人、分權限,得自己在 Administration 裡建使用者。密碼只在第一次啟動時由 .env 設定,之後改 .env 不會生效,要在畫面上改
連線不加密 3000 埠是 HTTP,登入的密碼在內網是明文傳送。它靠的是防火牆的來源限制,和 ClickHouse 一樣假設管理者的電腦在可信任的網段
警示沒有設定 Grafana 有警示功能,但安裝包沒有設任何規則,也沒有設通知管道。本系列裡「有事要通知人」走的是主機 A 的案件流程,不是這裡
會自己往外連 它會定期連 grafana.com 檢查本體與外掛有沒有新版,登入頁因此會顯示有新版可用;Grafana 預設還會回報匿名的使用統計,安裝包沒有關掉。第一次啟動時要從 grafana.com 下載 ClickHouse 外掛,主機 B 當時連不出去的話,外掛裝不起來,資料來源就不能用
不會自己更新 本體的版本跟著安裝包走

把它停掉會怎樣,實測過一次:停止 Grafana 容器 14 秒。這段期間 3000 埠連不上;對 WAF 送的攻擊請求照常回 403,那一筆事件照常寫進 ClickHouse,經 tunnel 的對外服務照常。重新啟動後約 14 秒可以登入,儀表板與資料來源都在。

所以它在整體裡的位置是這樣的:事件怎麼來、存在哪裡、誰來判斷,都和它無關;它只負責把 ClickHouse 裡已經有的東西,換成一眼看得出多寡與起伏的畫面。少了它,資料一筆都不會少,只是要看的時候得回去下 SQL。

七、怎麼確認它在做事

先看它活著沒有。這個端點不必登入:

# 主機 B
curl -s http://127.0.0.1:3000/api/health
{
  "database": "ok",
  "version": "11.3.0",
  "commit": "d9455ff7db73b694db7d412e49a68bec767f2b5a"
}

這裡的 database 指的是 Grafana 自己的資料庫,不是 ClickHouse。它顯示 ok,只代表 Grafana 本身正常。

通往 ClickHouse 的線通不通,在畫面上看:Connections → Data sources → ClickHouse-secstack,拉到最下面按 Save & test,出現 Data source is working 就是通的。

最後從 ClickHouse 那一側看有沒有人在用它。Grafana 發出的每一個查詢,ClickHouse 都記下了是哪個程式、替哪個 Grafana 使用者發的:

SELECT extract(client_name, 'grafana_user:([^;]+)') AS grafana_user, count() AS n
FROM system.query_log
WHERE client_name LIKE 'grafana%' AND type = 'QueryFinish'
  AND event_time > now() - INTERVAL 1 DAY
GROUP BY grafana_user;
   ┌─grafana_user─┬──n─┐
1. │ admin        │ 28 │
   └──────────────┴────┘

查不到任何一列,代表過去一天沒有人開過 Grafana 的任何面板。在剛裝好、還沒建儀表板的節點上,這是正常的結果,也正是本篇開頭那句話的意思:線接好了,畫面還沒有人畫。

看 Grafana 的紀錄時,可能會遇到零星的 database is locked。那是它自己的資料庫在主機磁碟忙碌時一時寫不進去,背景工作下一輪會再做,不必處理。實測一台節點上,這個訊息只集中出現在安裝當天與更新當天。


上一篇
cloudflared:由主機 B 往外撥出的對外入口
系列文
一鍵完成六套開源防禦系統整合 共 24 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言