授權掃描網段(Scan Zone Manage)¶
功能群:系統管理|三層 RBAC 模型先讀 功能群總覽 §2
事實基準:2026-10-05 從 FE
src/views/scan-zone/、jedi-detectionapi/routes/scan_zone_route.py/app/service/scan_zone_service.py、BEcore/plugins/detection.py、DEVcompliance.tenant_scan_zones實查掃出
變更紀錄¶
| 日期 | FR | 變更 |
|---|---|---|
| 2026-10-05 | FR-129 | 新頁:租戶登記授權掃描網段;網段型掃描目標必須整段落在已授權網段內,agent 端心跳也拿這份清單做連線前比對 |
1. 功能描述¶
授權掃描網段是檢測線的授權範圍設定頁:客戶 IT 在這裡登記「貴單位准許被掃描的網段」(通常一到五條 CIDR)。這份清單有兩個消費者:
- 雲端存檔與派工守門:任務配置裡的網段型掃描目標(Nmap
targets、OpenVAShosts)必須整段落在本頁「已授權」的網段內,否則存檔與派工都被擋(DETECTION_TOOLS_400024)。 - agent 端二次比對:雲端心跳把「設備清冊內網 IP+本頁已授權網段」下發給 agent(見檔案 Agent 管理 §6.6),agent 每次連線前自己比對,清冊外、網段外一律拒連。雲端被打穿時,這一層照樣擋。
逐台型目標(CINC Auditor/GCB/OpenSCAP 的 hosts、Nmap 的執行主機)不看本頁,看設備清冊。兩條規則的分工見 任務配置頁「Agent 分派區塊」。
列有兩種狀態:
| 狀態 | 畫面 | 算不算授權 | 從哪來 |
|---|---|---|---|
active |
綠色「已授權」 | 算 | 人工新增,或把待確認列按「確認授權」 |
pending |
黃色「待確認」 | 不算 | 按「依 Agent 位址產生建議」,由系統依 agent 所在內網位址推 /24(IPv6 推 /64) |
主要使用者:租戶管理員(持 scan-zone.update)。能派掃描的人(plugin.update)預設沒有本頁權限——不能自己擴大可掃範圍。
角色速覽
| 角色 | 一句話 |
|---|---|
租戶管理員(scan-zone.read+scan-zone.update,seed 只配給 is_admin 角色) |
唯一可增刪改、確認建議的人 |
只有 scan-zone.read 的角色 |
看得到清單、所有按鈕隱藏,頁上提示「修改需要租戶管理員權限」 |
| 其他使用者 | 選單不出現;手打網址會被導回首頁 |
1.1 功能總覽(本頁全部功能)¶
| # | 功能 | 說明 | 位置 | 詳述 |
|---|---|---|---|---|
| 1 | 網段清單 | 依租戶列出全部網段(待確認排最前),欄位:功能/網段/狀態/說明/最後異動(時間+暱稱) | 主表格 | §5 |
| 2 | 新增網段 | Dialog 填網段(必填)+說明;新增一律 active |
Header「新增網段」 | UC-SZ-01 |
| 3 | 編輯網段 | 同一 Dialog 改網段或說明 | 列上「編輯」 | UC-SZ-01 |
| 4 | 刪除網段 | 確認框後刪除;刪除後網段型目標落在這段的任務存檔與派工會被擋 | 列上「刪除」 | UC-SZ-01 |
| 5 | 依 Agent 位址產生建議 | 對本租戶每台 agent 的內網位址推一筆 pending;已被涵蓋或重複的略過 |
Header 按鈕 | UC-SZ-02 |
| 6 | 確認授權 | pending → active;說明欄尾端「(待確認)」字樣自動拿掉 |
待確認列的綠色勾 | UC-SZ-02 |
| 7 | 授權唯讀模式 | 授權到期進唯讀時寫入按鈕 disabled,tooltip 說明原因 | 全部寫入按鈕 | §4 |
2. Use Case¶
視覺慣例:判斷框=分支條件;擋下=標 error code;成功終點=寫入完成。
UC-SZ-01 新增/編輯/刪除網段¶
| 項目 | 內容 |
|---|---|
| 角色 | 持 scan-zone.update |
| 前置條件 | 已登入;頁面可見 |
| 產出 / 後置條件 | compliance.tenant_scan_zones 寫一列;稽核事件一筆;寄信通知該租戶全部管理員 |
流程:
- 填網段 → 後端正規化:
- 不是合法網段,或主機位元非零(
10.1.2.3/16)→ 400DETECTION_TOOLS_400022,不自動截成10.1.0.0/16(自動放大範圍等於替使用者多授權一大段)。 - 單一 IP 視為
/32(IPv6/128)。 - 同租戶已有同一網段 → 409
DETECTION_TOOLS_409020。 - 寫入後記稽核事件:新增
SCAN_ZONE_CREATED(6127)、修改與確認SCAN_ZONE_UPDATED(6128)、刪除SCAN_ZONE_DELETED(6129),內容帶改前改後的網段、狀態、說明。 - 寄信通知該租戶全部管理員(「誰、加/改/刪/確認、哪一段」)。寄信失敗只記錯誤日誌,不回滾已寫入的授權變更。
UC-SZ-02 依 Agent 位址產生建議並確認¶
| 項目 | 內容 |
|---|---|
| 角色 | 持 scan-zone.update |
| 前置條件 | 本租戶已有註冊過的 agent |
| 產出 / 後置條件 | 新增 0~N 筆 pending;確認後轉 active |
流程:
- 逐台取 agent 位址:agent 自報的內網 IP 優先(
hardware_info.ip),沒有才用雲端看到的連線來源 IP(經 NAT 時可能是閘道)。 - 不是內網位址(公網、loopback、未指定)→ 略過;推公網 IP 的 /24 等於替人授權別人的網段。
- 推出的網段已存在、或已被某筆
active網段整段涵蓋 → 略過。重複按不會重複建。 - 建成
pending,說明預設「agent <名稱> 所在網段(待確認)」,source_agent_uid記來源 agent。建議本身不寫稽核、不寄信——真正的授權變更發生在確認那一刻。 - 管理員按「確認授權」→
PUT status=active→ 記 6128(action=confirm)+寄信。 active改回pending一律拒絕(400DETECTION_TOOLS_400023);要收回授權就刪除。
3. 權限矩陣¶
| 操作 | FE 判定 | BE 強制 | BE 檢查位置 |
|---|---|---|---|
| 選單可見 | ui_routes 的 scan-zone(掛在「系統管理」群,排在設備管理之後) |
— | web-menu |
| 進頁/讀清單 | hasCap('scan-zone.read'),無則導回首頁 |
capability_required(scan-zone.read) |
scan_zone_route.py::ScanZonesRoute.get |
| 新增/編輯/刪除/產生建議/確認 | hasCap('scan-zone.update'),無則按鈕與功能欄隱藏 |
capability_required(scan-zone.update) |
ScanZonesRoute.post、ScanZoneDetailRoute.put/delete、ScanZoneSuggestRoute.post |
| 租戶歸屬 | — | 租戶一律取自登入身分,body 帶的租戶不收;改刪先比對該列 tenant_id,他租戶的 uid 回 404 DETECTION_TOOLS_404009;資料庫 RLS 再擋一道 |
scan_zone_service.py::_get_owned |
| 授權(license) | useLicenseReadonly |
require_license("scan-zone"),scan-zone 列在授權豁免清單(基礎設施設定,不隨販售模組開關) |
common/authz/license.py |
分權是本頁的設計重點:執行掃描(
plugin.update/任務執行權限)、改設備清冊(device.*)、改授權網段(scan-zone.update)是三顆不同的能力點。三者都落在同一個帳號上,帳號被盜時攻擊者可以「先擴大範圍再掃」;分開之後每一步都要不同的帳號,而且改網段會留事件、發信。手冊建議見檢測 Agent 手冊「檢測目標授權範圍」。
4. 狀態機與前置條件¶
(產生建議)──▶ pending ──(確認授權)──▶ active
│ │
└──────(刪除)◀──────────┘
人工新增 ─────────────────────────────▶ active
active ──▶ pending:拒絕(DETECTION_TOOLS_400023)
| 條件 | 效果 | 出處 |
|---|---|---|
| 主機位元非零/不是網段 | 400 DETECTION_TOOLS_400022 |
scan_zone_service.py::normalize_cidr |
| 同租戶同網段已存在 | 409 DETECTION_TOOLS_409020 |
_assert_cidr_free |
status 不是 active/pending,或 active→pending |
400 DETECTION_TOOLS_400023 |
update_zone |
| 授權到期唯讀 | 寫入按鈕 disabled(writeDisabled()) |
ScanZoneManage.vue |
5. UI 設計¶
單頁:Header(標題+「依 Agent 位址產生建議」+「新增網段」)、藍色說明列、DataTable、新增/編輯 Dialog。
| 欄 | 內容 |
|---|---|
功能(只對 scan-zone.update 顯示) |
待確認列多一顆綠色勾「確認授權」;編輯;刪除 |
| 網段 | 正規化後的 CIDR,粗體 |
| 狀態 | Tag:已授權(綠)/待確認(黃) |
| 說明 | 自由文字,最長 255 |
| 最後異動 | YYYY-MM-DD HH:mm+修改者暱稱(暱稱查不到才顯示帳號) |
Dialog:網段(必填,placeholder「例如 192.168.50.0/24」,下方提示「主機位元必須為零」)、說明(選填)。錯誤由全域 interceptor 依 error code 顯示,Dialog 留著讓使用者改。
確認與刪除都走確認框;確認框文字明講後果(確認:「確認後檢測工具即可掃描此網段內的主機」;刪除:「刪除後檢測工具將不能再掃描此網段」)。
6. API 規格¶
Envelope 見功能群總覽。全部端點屬 jedi-detection 套件 routing,宿主不另掛 route。
6.1 總清單¶
| Method + Path | 說明 | 能力點 |
|---|---|---|
GET /scan-zones |
列出本租戶網段(待確認排最前) | scan-zone.read |
POST /scan-zones |
新增(一律 active) |
scan-zone.update |
PUT /scan-zones/{uid} |
改網段/說明,或 status=active 確認建議 |
scan-zone.update |
DELETE /scan-zones/{uid} |
刪除 | scan-zone.update |
POST /scan-zones/suggest-from-agents |
依 agent 位址產生 pending 建議,回傳新建的列 |
scan-zone.update |
6.2 回應欄位(ScanZoneResponseSchema)¶
| 欄位 | 型別 | 說明 |
|---|---|---|
| uid | string | 對外識別碼 |
| cidr | string | 正規化後的網段 |
| label | string|null | 說明 |
| status | string | active/pending |
| source_agent_uid | string|null | 建議來源 agent(人工新增為 null) |
| created_user / updated_user | string|null | 帳號 |
| created_user_name / updated_user_name | string|null | 暱稱 |
| created_at / updated_at | datetime |
6.3 寫入 Request¶
| 端點 | 欄位 | 說明 |
|---|---|---|
| POST | cidr(必填)、label |
未知欄位忽略(unknown=EXCLUDE) |
| PUT | cidr、label、status |
只套用 body 有帶的欄位;label 帶空字串=清空 |
6.4 錯誤碼¶
| 碼 | HTTP | 情境 |
|---|---|---|
DETECTION_TOOLS_400022 |
400 | 網段格式錯或主機位元非零 |
DETECTION_TOOLS_400023 |
400 | 狀態值不合法,或把已授權改回待確認 |
DETECTION_TOOLS_404009 |
404 | 網段不存在或不屬本租戶 |
DETECTION_TOOLS_409020 |
409 | 同一網段已登記 |
本頁的網段被使用時(任務存檔/派工),網段外的目標回 DETECTION_TOOLS_400024,見任務配置。
7. 前端檔案地圖(compliance-manager-fe/)¶
| 檔案 | 角色 |
|---|---|
src/views/scan-zone/ScanZoneManage.vue |
主頁:清單、產生建議、確認、刪除、能力點判定 |
src/views/scan-zone/ScanZoneDialog.vue |
新增/編輯 Dialog |
src/service/ScanZoneService.js |
API 包裝 |
src/config/scanZone.js |
能力點常數 SCAN_ZONE_READ/SCAN_ZONE_UPDATE |
src/config/router/index.js |
route scan-zone,path /system/scan-zone |
src/config/locales/i18n/{zh-tw,en}/scan-zone.json |
頁面字串 |
8. 後端檔案地圖¶
| 層 | 檔案 |
|---|---|
| Route | jedi-detection api/routes/scan_zone_route.py(三個 Resource)、api/routing.py 註冊 |
| App service | jedi-detection app/service/scan_zone_service.py::ScanZoneService(全部 @transaction) |
| Domain | jedi-detection domain/scan_zone/service/scan_zone_domain_service.py(contains/zones_contain:目標整段落在 active 網段內才算,IPv4/IPv6 版本不同直接不算) |
| 宿主 adapter | BE core/plugins/detection.py(通知寄送、agent 目錄、身分暱稱);core/plugins/remote_agent.py::AllowedTargetsProvider(心跳下發,讀同一張表的 active 列) |
| 稽核事件碼 | BE common/enum/event_code.py、jedi-detection common/event_code.py(6127~6129) |
9. DB¶
9.1 資料表¶
| 表 | 讀/寫 | 說明 |
|---|---|---|
| compliance.tenant_scan_zones | 寫 | 本頁唯一寫入表 |
| compliance.remote_agents | 讀 | 產生建議時取 agent 位址 |
| public.users | 讀 | 審計欄暱稱 |
9.2 compliance.tenant_scan_zones¶
| 欄位 | 型別 | 說明 |
|---|---|---|
| id | bigint | PK |
| uid | varchar(36) | 對外識別碼,UNIQUE |
| tenant_id | integer NOT NULL | → tenants.id(ON DELETE CASCADE) |
| org_unit_id | integer|null | → org_units.id |
| cidr | cidr NOT NULL | 網段;(tenant_id, cidr) UNIQUE |
| label | varchar(255)|null | 說明 |
| status | varchar(16) NOT NULL default active |
CHECK active/pending |
| source_agent_uid | varchar(36)|null | 建議來源 agent |
| created_user / updated_user | varchar(255)|null | 審計欄 |
| created_at / updated_at | timestamptz NOT NULL |
RLS policy tenant_scan_zones_tenant_isolation:super admin 或 app_tenant_allowed_for_session(tenant_id)。索引 (tenant_id, status) 供心跳與守門查 active 列。
Migration:scripts/sql/2026-10-05-fr129-2-tenant-scan-zones.sql(表、RLS、能力點 scan-zone.read/scan-zone.update 只配 is_admin 角色、選單)。
10. 頁面邏輯與資料對應¶
- 載入:
onMounted先判scan-zone.read,沒有就router.replace('/');有才GET /scan-zones。 - 寫入後一律重新
GET整份清單(清單很短,不做局部更新)。 - 產生建議回傳新建列數:>0 顯示「已新增 N 筆待確認建議」,=0 顯示「所有 Agent 所在網段都已登記」。
- 錯誤由全域 interceptor 依 error code 顯示 i18n 訊息,頁面不另處理。
11. 背景行為與外部依賴¶
| 類型 | 內容 |
|---|---|
| 通知 | 每次新增/修改/確認/刪除寄信給該租戶全部管理員;產生建議不寄 |
| 稽核 | 6127/6128/6129 落 system_logs,帶改前改後值 |
| 心跳下發 | agent 每次心跳,雲端把本租戶 active 網段連同設備清冊內網 IP 組成授權目標清單;清單內容變了版本號就變,agent 帶舊版本時拿到整份新清單。本頁改動最慢一個心跳週期後生效到 agent 端 |
| jedi-* 套件 | jedi-detection(本頁全部 domain/route)、jedi-remote-agent(心跳下發的 port) |
12. 邊界情況與已知坑¶
- 待確認不算授權,兩端判準一致:雲端守門(
DetectionTargetAuthorizer)與心跳下發(AllowedTargetsProvider)都只看active。兩邊寬窄不同會出現「雲端准派、agent 拒連」,改任一邊都要同步另一邊。 - 刪除網段不會改已存的任務設定:已存在任務裡落在被刪網段的目標,下次存檔或派工時才被擋(
DETECTION_TOOLS_400024);已在 agent 手上排程的工作,agent 下一次心跳拿到新清單後也會拒連。 - 建議用 agent 自報 IP,經 NAT 可能推錯:agent 沒自報內網 IP 時退回雲端看到的連線來源;那是閘道位址時,推出來的 /24 不是 agent 真正所在網段。建議只是建議,確認前請核對。
- 建議不是在 agent 註冊當下自動產生:要管理員按按鈕。已註冊的 agent 也能補產。
- 逐台型目標不看本頁:CINC Auditor/GCB/OpenSCAP 的
hosts與 Nmap 執行主機只驗「在設備清冊內且為內網位址」,不要求落在授權網段內(存量任務遷移時自動建的設備可能不在任何網段內,要求落在網段內會讓存量任務整批無法執行)。
13. 開發與驗證¶
- 導航路徑:租戶管理員登入 → 系統管理 → 授權掃描網段(
/system/scan-zone) - 測試帳號:租戶管理員(角色有
is_admin旗標);對照組用一般 IT Manager 確認選單不出現、手打網址導回首頁。密碼見.env/部署文件 - 驗收:新增
192.168.50.0/24→system_logs有 6127、管理員收到信;輸入10.1.2.3/16→ 400022;按產生建議 → 出現待確認列 → 確認 → 轉已授權 - 相關文件:設計決策 D1~D7 在 FR-129 母卡(Notion CM-2485);手冊見檢測 Agent 手冊第十二章