API 使用手冊API manual
jt-ipam 的 REST API、phpIPAM 相容層、Graylog 查表與 MCP。以下所有網址請把 https://ipam.example.com 換成你自己的位址。
The jt-ipam REST API, phpIPAM compatibility layer, Graylog lookups and MCP. Replace https://ipam.example.com below with your own address.
curl 要加 -k(或把 CA 加進信任庫)。
The API is HTTPS-only. jt-ipam enforces HTTPS and does not serve plain HTTP. If your instance uses a self-signed certificate, add -k to curl (or add the CA to your trust store).
1認證:API 權杖Auth: API tokens
外部程式一律用 API 權杖,不要用帳號密碼登入拿 JWT(JWT 只有 15 分鐘、是給網頁前端用的)。 External programs should always use an API token rather than logging in for a JWT (JWTs last 15 minutes and exist for the web UI).
怎麼取得權杖Getting a token
登入 jt-ipam → 右上角使用者選單 → API 權杖 → 新增。填名稱、有效天數(1~365,預設 90)、權限範圍,按儲存。 Sign in to jt-ipam → user menu (top right) → API tokens → Add. Give it a name, a lifetime (1–365 days, default 90) and a scope, then save.
怎麼帶權杖Sending the token
curl -H "Authorization: Bearer jt_prod_xxxxxxxxxxxxxxxx" \
https://ipam.example.com/api/v1/subnets
權杖首碼 jt_ 會讓後端自動辨識為 API 權杖(沒有這個首碼則當成 JWT 解析)。
The jt_ prefix tells the backend this is an API token (without it, the value is parsed as a JWT).
權限範圍(scope)Scopes
| scopes | 效果Effect |
|---|---|
[] |
不限制 —— 沿用權杖擁有者的權限,可讀可寫。 Unrestricted — inherits the owner's permissions, read and write. |
["read"] |
唯讀 —— GET/HEAD/OPTIONS 可用;POST/PATCH/PUT/DELETE 一律回 403。
Read-only — GET/HEAD/OPTIONS work; POST/PATCH/PUT/DELETE always return 403. |
目前只支援這兩種。填其他值(例如 write、subnets:read)建立時就會被拒絕回 422 —— 這是刻意的:不提供無法真正強制執行的權限旋鈕。
These are the only two supported. Any other value (e.g. write, subnets:read) is rejected with 422 at creation — deliberately, so there is no knob that looks like a restriction but isn't enforced.
object_filters 欄位目前保留但不生效,別依賴它。
A token inherits its owner's permissions. A token created by an admin is a full-privilege admin key. To give a third party restricted access: create a low-privilege user, grant it the objects it needs (sections / subnets / devices…) under Admin → Permissions, then sign in as that user to create the token. The object_filters field is reserved but not enforced — do not rely on it.
用 API 管理權杖Managing tokens via the API
| 方法Method | 路徑Path | 說明Description |
|---|---|---|
| GET | /api/v1/api-tokens |
列出自己的權杖(admin 可加 ?user_id= 看別人的)List your own tokens (admins may add ?user_id=) |
| POST | /api/v1/api-tokens |
建立,回應含一次性明文Create; the response carries the one-time plaintext |
| DELETE | /api/v1/api-tokens/{id} |
撤銷(立即失效,不可復原)Revoke (immediate, irreversible) |
curl -X POST https://ipam.example.com/api/v1/api-tokens \
-H "Authorization: Bearer <jwt-or-token>" \
-H "Content-Type: application/json" \
-d '{"name":"monitoring","expires_in_days":180,"scopes":["read"]}'
{
"id": "3f1c...", "name": "monitoring",
"token": "jt_prod_XXXXXXXXXXXXXXXXXXXX",
"token_prefix": "jt_prod_", "expires_at": "2027-01-26T00:00:00Z",
"scopes": ["read"]
}
2通用慣例Conventions
- 基底路徑:
/api/v1。所有請求與回應都是 JSON(Content-Type: application/json),除少數明講的 CSV 端點。 Base path:/api/v1. Requests and responses are JSON (Content-Type: application/json), apart from a few explicitly-CSV endpoints. - 識別碼是 UUID,不是遞增整數。 Identifiers are UUIDs, not incrementing integers.
- 時間一律 ISO 8601、UTC(
2026-07-30T12:34:56Z)。 Timestamps are ISO 8601 in UTC (2026-07-30T12:34:56Z). - 未知欄位會被拒絕。寫入用的 schema 是嚴格模式(
extra=forbid)—— 多送一個拼錯的欄位會回422,而不是安靜忽略。 Unknown fields are rejected. Write schemas are strict (extra=forbid) — a misspelled extra field returns422instead of being silently ignored. - 部分更新用
PATCH,只送要改的欄位。 UsePATCHfor partial updates, sending only the fields you want to change.
分頁Pagination
列表端點吃 page(從 1 起算)與 page_size,回應固定是這個外層:
List endpoints take page (1-based) and page_size, and always return this envelope:
{ "items": [ … ], "total": 1234, "page": 1, "page_size": 50 }
page_size 上限視端點而定(多數是 200)。要抓完整資料就依 total 逐頁取。
The page_size cap depends on the endpoint (usually 200). To fetch everything, page through using total.
3錯誤與狀態碼Errors & status codes
錯誤回應一律是 {"detail": "…"};422 另外附 errors 陣列指出哪個欄位不合法。伺服器端不會回 stack trace。
Errors are always {"detail": "…"}; 422 additionally carries an errors array pinpointing the invalid fields. Stack traces are never returned.
{ "detail": "Invalid request",
"errors": [ { "loc": ["body","cidr"], "msg": "value is not a valid IPv4 network", "type": "value_error" } ] }
| 狀態Status | 意義與常見原因Meaning & common cause |
|---|---|
200 / 201 / 204 | 成功(204 用於刪除,無內容)Success (204 for deletes, no body) |
401 | 沒帶權杖、權杖無效、已撤銷或已到期Missing, invalid, revoked or expired token |
403 | 認證過但不准 —— RBAC 不足,或是唯讀權杖試圖寫入Authenticated but not allowed — insufficient RBAC, or a read-only token attempting a write |
404 | 不存在 —— 也用於「存在但你無權看見」,以免洩漏存在性Not found — also returned for "exists but you may not see it", to avoid leaking existence |
409 | 衝突,例如重疊網段、或刪除仍被引用的物件Conflict, e.g. overlapping subnets, or deleting a still-referenced object |
422 | 欄位驗證失敗(含未知欄位、不支援的 scope)Validation failed (including unknown fields and unsupported scopes) |
429 | 超過速率限制,回應帶 Retry-AfterRate limited; the response carries Retry-After |
4權限模型Permission model
jt-ipam 是預設關閉(deny by default)。你的權杖看得到什麼,完全取決於擁有者被授權了什麼: jt-ipam is deny by default. What your token can see depends entirely on what its owner has been granted:
- 可逐物件授權的資料(區段/子網路/IP/裝置/機櫃/地點/客戶)→ 只回你可見範圍內的,連
total、統計與趨勢都會跟著縮放。 Per-object data (sections / subnets / IPs / devices / racks / locations / customers) → only what you can see, andtotal, counts and trends scale with it. - 全域基礎設施資料(VLAN/VRF/NAT/防火牆/DNS/虛擬化/佈線/電力…)→ 需要「全域讀取」(admin 或萬用讀取授權)。只被指派特定物件的帳號會拿到
403。 Global infrastructure (VLAN / VRF / NAT / firewalls / DNS / virtualization / cabling / power…) → requires global read (admin or a wildcard read grant). Accounts scoped to specific objects get403. - 純管理資料(稽核記錄、使用者/群組/權限、系統與整合設定)→ 需要 admin。 Administrative data (audit log, users / groups / permissions, system and integration settings) → requires admin.
想知道自己這把權杖有什麼能力,打 GET /api/v1/me:回應含 is_admin、has_visibility、has_global_read。
To discover what your token can do, call GET /api/v1/me: the response includes is_admin, has_visibility and has_global_read.
5區段(Sections)Sections
最上層的分組容器,子網路掛在區段底下。可有父子階層。 The top-level grouping container that subnets belong to. Supports parent/child nesting.
| 方法Method | 路徑Path | 說明Description |
|---|---|---|
| GET | /api/v1/sections | 列出(分頁)List (paginated) |
| GET | /api/v1/sections/{id} | 單筆詳情Get one |
| POST | /api/v1/sections | 建立Create |
| PATCH | /api/v1/sections/{id} | 部分更新Partial update |
| DELETE | /api/v1/sections/{id} | 刪除Delete |
| POST | /api/v1/sections/bulk-delete | 批次刪除({"ids":[…]})Bulk delete ({"ids":[…]}) |
建立區段Create a section
| 欄位Field | 型別Type | 必填Required | 說明Description |
|---|---|---|---|
name | string | 是yes | 1~128 字1–128 chars |
description | string | — | 最多 1024 字up to 1024 chars |
parent_id | uuid | — | 上層區段Parent section |
customer_id | uuid | — | 歸屬客戶/管理單位Owning customer / managing unit |
strict_mode | bool | — | 嚴格模式Strict mode |
display_order | int | — | 顯示排序(0~10000)Display order (0–10000) |
curl -X POST https://ipam.example.com/api/v1/sections \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"name":"Taipei DC","description":"main site"}'
6子網路(Subnets)Subnets
| 方法Method | 路徑Path | 說明Description |
|---|---|---|
| GET | /api/v1/subnets | 列出。可加 section_id、archived、page、page_sizeList. Accepts section_id, archived, page, page_size |
| GET | /api/v1/subnets/{id} | 單筆詳情Get one |
| GET | /api/v1/subnets/{id}/usage | 使用率統計(已用/可用/可配發)Usage stats (used / free / usable) |
| GET | /api/v1/subnets/{id}/first_free_address | 第一個可用 IPFirst free IP |
| POST | /api/v1/subnets | 建立Create |
| PATCH | /api/v1/subnets/{id} | 部分更新Partial update |
| POST | /api/v1/subnets/{id}/archive | 封存 / /unarchive 取消封存Archive / /unarchive to restore |
| POST | /api/v1/subnets/{id}/scan | 要求掃描代理立刻掃一次Ask the scan agent to sweep it now |
| DELETE | /api/v1/subnets/{id} | 刪除(底下仍有 IP/下層時會被擋)Delete (blocked while it still holds IPs or children) |
| GET | /api/v1/subnets/overlaps/exists | 是否存在重疊網段(admin)Whether any overlapping subnets exist (admin) |
/usage,不要自己算 CIDR。jt-ipam 的「已用/可用」是依實際 IP 記錄與網段設定算的,跟純數學的 CIDR 容量不一樣(會扣掉網路位址、廣播位址、保留與 DHCP 範圍等)。
Use /usage rather than computing from the CIDR. jt-ipam's used/free figures come from the actual IP records and subnet settings, which differ from raw CIDR arithmetic (network and broadcast addresses, reservations, DHCP pools and so on).
curl -X POST https://ipam.example.com/api/v1/subnets \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"cidr":"192.0.2.0/24","section_id":"<section-uuid>","description":"office LAN"}'
7IP 位址(Addresses)IP addresses
| 方法Method | 路徑Path | 說明Description |
|---|---|---|
| GET | /api/v1/addresses | 列出/查詢(見下方參數)List / query (parameters below) |
| GET | /api/v1/addresses/{id} | 單筆詳情Get one |
| GET | /api/v1/addresses/{id}/history | 異動記錄Change history |
| GET | /api/v1/addresses/{id}/relations | 關聯物件Related objects |
| GET | /api/v1/addresses/{id}/switch-port | 對應的交換器連接埠The switch port it is seen on |
| GET | /api/v1/addresses/export.csv | 匯出 CSVExport as CSV |
| POST | /api/v1/addresses | 建立Create |
| POST | /api/v1/addresses/first_free | 取得並配發第一個可用 IPClaim the first free IP |
| PATCH | /api/v1/addresses/{id} | 部分更新Partial update |
| DELETE | /api/v1/addresses/{id} | 刪除Delete |
| POST | /api/v1/addresses/bulk-state | 批次改狀態Bulk state change |
| POST | /api/v1/addresses/import | 批次匯入Bulk import |
查詢參數Query parameters
| 參數Parameter | 說明Description |
|---|---|
subnet_id | 限定某個子網路Restrict to one subnet |
section_id | 限定某個區段Restrict to one section |
customer_id | 限定某個客戶/管理單位Restrict to one customer |
device_id | 限定掛在某個裝置上Restrict to one device |
q | 關鍵字(IP、主機名稱、MAC、說明…)Free text (IP, hostname, MAC, description…) |
exact | 精準比對而非模糊Exact match instead of fuzzy |
sort / order | 排序欄位 / asc|descSort field / asc|desc |
# 查某網段裡所有 IP
curl -G https://ipam.example.com/api/v1/addresses \
-H "Authorization: Bearer $TOKEN" \
--data-urlencode "subnet_id=<subnet-uuid>" --data-urlencode "page_size=200"
# 依主機名稱找
curl -G https://ipam.example.com/api/v1/addresses \
-H "Authorization: Bearer $TOKEN" --data-urlencode "q=web01"
192.168.1.0/24)的環境裡,同一個 IP 會跨多個子網路各有一筆 —— 這是設計如此。用 subnet_id 限定範圍,不要假設 IP 唯一。
The same IP string may appear more than once. The unique key is (subnet, IP), so with overlapping subnets (different customers sharing 192.168.1.0/24) one IP legitimately has a row per subnet. Scope your queries with subnet_id; don't assume an IP is unique.
8裝置(Devices)Devices
| 方法Method | 路徑Path | 說明Description |
|---|---|---|
| GET | /api/v1/devices | 列出List |
| GET | /api/v1/devices/{id} | 單筆詳情Get one |
| GET | /api/v1/devices/{id}/relations | 關聯(IP/機櫃/佈線…)Relations (IPs / rack / cabling…) |
| GET | /api/v1/devices/{id}/integrations | 各整合帶回的資料Data pulled in by integrations |
| GET | /api/v1/devices/{id}/vlans | VLAN 對應VLAN mappings |
| POST | /api/v1/devices | 建立Create |
| PATCH | /api/v1/devices/{id} | 部分更新Partial update |
| DELETE | /api/v1/devices/{id} | 刪除Delete |
9搜尋與 IP 工具Search & IP tools
GET /api/v1/search?q=…&limit_per_type=… 是全域搜尋,跨區段/子網路/IP/裝置/客戶等型別,並依你的可見範圍過濾。支援部分 MAC 首碼(如 bc:24)。
GET /api/v1/search?q=…&limit_per_type=… searches across sections, subnets, IPs, devices, customers and more, filtered to what you may see. Partial MAC prefixes (e.g. bc:24) work.
/api/v1/tools/* 是一組無副作用的計算端點,適合腳本直接呼叫:
/api/v1/tools/* is a set of side-effect-free calculators handy for scripts:
| 端點Endpoint | 用途Purpose |
|---|---|
ip-info / cidr-info | IP/網段基本資訊IP / CIDR facts |
cidr-split / aggregate | 切分 / 聚合網段Split / aggregate prefixes |
ip-in-cidr / cidr-relation | 包含關係判斷Containment and relation checks |
range-to-cidr / cidr-to-range | 範圍 ↔ 網段互轉Range ↔ CIDR conversion |
netmask / eui64 / mac-format | 遮罩換算、EUI-64、MAC 格式化Netmask conversion, EUI-64, MAC formatting |
dns-lookup / fqdn / dns-mail / geoip | DNS 查詢、FQDN 解析、郵件記錄、GeoIPDNS lookups, FQDN parsing, mail records, GeoIP |
10完整資源索引Full resource index
API 共約 500 條路由。上面詳述的是最常用的核心資源;其餘資源大多遵循同一套 GET 列表 / GET {id} / POST / PATCH / DELETE 慣例。
The API has roughly 500 routes. The sections above cover the core resources in detail; most others follow the same GET list / GET {id} / POST / PATCH / DELETE convention.
| 分類Area | 基底路徑Base paths | 權限Access |
|---|---|---|
| 核心 IPAMCore IPAM | /sections /subnets /addresses /devices /customers /racks /locations |
逐物件可見性Per-object visibility |
| 網路資源Network resources | /vlans /vlan-domains /vrfs /asns /nat /dhcp-ranges /vpn-tunnels /wireless |
全域讀取Global read |
| 實體層Physical layer | /cables /cable-terminations /device-ports /ports /power-feeds /power-panels /power-outlets /device-power-ports |
全域讀取Global read |
| 商務/組織Business / org | /tenants /tenant-groups /providers /circuits /circuit-types /contacts /contact-groups /contact-assignments |
全域讀取Global read |
| 整合Integrations | /firewalls(OPNsense)/pfsense /fortigate /windows-dhcp /librenms /wazuh /adguard /dns /virt |
設定需 admin;唯讀檢視需全域讀取admin to configure; global read to view |
| 代理與憑證Agents & certificates | /scan-agents /cert-agents /certificates /ssh-credentials |
admin |
| 流程與通知Workflow & notifications | /ip-requests /notifications /webhooks /tasks /anomalies /ip-changes |
視端點而定Varies |
| 分析與 AIAnalytics & AI | /dashboard /topology /search /tools /oui /ai |
視端點而定Varies |
| 管理Administration | /users /groups /audit /system /custom-fields /plugins /import /migration |
admin |
| 自助Self-service | /me /me/preferences /api-tokens /auth |
任何已認證帳號Any authenticated account |
11phpIPAM 相容 API-compatible API
給既有的 phpIPAM 腳本用的相容層:換掉網址與權杖就能沿用,回應是 phpIPAM 的外層格式。 A compatibility layer for existing phpIPAM scripts: change the URL and token and they keep working, with phpIPAM-shaped response envelopes.
基底路徑:/api/phpipam/<app_id>/。<app_id> 沿用你原本 phpIPAM 的 App ID 字串。
Base path: /api/phpipam/<app_id>/, where <app_id> is whatever App ID string your scripts already use.
認證Authentication
三種標頭都收(挑一個就好):token: jt_…、phpipam-token: jt_…、Authorization: Bearer jt_…。也可以用帳號密碼走 Basic Auth 換一把 30 天的權杖:
Any one of three headers works: token: jt_…, phpipam-token: jt_…, or Authorization: Bearer jt_…. You can also exchange username/password over Basic Auth for a 30-day token:
curl -X POST -u 'user:password' \
https://ipam.example.com/api/phpipam/myapp/user/
{ "code":200, "success":true, "data":{ "token":"jt_prod_…", "expires":"…" }, "time":0.01 }
| 方法Method | 路徑(接在基底之後)Path (after the base) | 說明Description |
|---|---|---|
| POST | user/ | Basic Auth 換權杖Exchange Basic Auth for a token |
| GET | user/ | 權杖資訊Token info |
| PATCH | user/ | 延長權杖期限Extend the token |
| DELETE | user/ | 撤銷權杖(登出)Revoke the token (log out) |
| GET | sections/ · sections/{id} · sections/{id}/subnets/ | 區段Sections |
| GET | subnets/{id}/ · subnets/cidr/{cidr}/ · subnets/{id}/usage/ · subnets/{id}/first_free/ · subnets/{id}/addresses/ | 子網路Subnets |
| GET | addresses/{id}/ · addresses/{ip}/{subnet_id}/ · addresses/search/{ip}/ · addresses/search_hostname/{host}/ · addresses/first_free/{subnet_id}/ | IP 位址IP addresses |
POST PATCH DELETE sections/ · subnets/ · addresses/ | 建立/更新/刪除Create / update / delete | |
docs/PHPIPAM_API_MAPPING.md。新寫的整合建議直接用上面的原生 REST API。
The layer covers the commonly-used subset of the phpIPAM API, not every call. See docs/PHPIPAM_API_MAPPING.md in the source for the full mapping. For new integrations, prefer the native REST API above.
POST/PATCH 會被擋成 403。唯一例外是 DELETE user/(撤銷自己的權杖)—— 那是降權、不是異動資料,所以照樣放行,老腳本的「登入 → 查詢 → 登出」流程不會斷。
Read-only tokens are enforced here too: POST/PATCH get 403. The one exception is DELETE user/ (revoking your own token) — that reduces privilege rather than changing data, so it is allowed and the classic login → query → logout flow keeps working.
12Graylog DSV 查表 lookups
給 Graylog 的「DSV File from HTTP」配接器用的免登入唯讀端點,回 CSV。認證是一把系統層級的權杖,走網址參數 ?token=(由 admin 在「管理 → Graylog DSV」產生),因為 Graylog 抓檔時不能帶自訂標頭。
Unauthenticated, read-only CSV endpoints for Graylog's "DSV File from HTTP" adapter. They are gated by a system-level token passed as ?token= (generated under Admin → Graylog DSV), because Graylog cannot send custom headers when fetching.
| 路徑Path | 對照Mapping |
|---|---|
/api/v1/lookup/{name} | IP → 主機名稱IP → hostname |
/api/v1/lookup/firewall/{id}/rule-aliases | OPNsense 規則 rid → 別名OPNsense rule rid → alias |
/api/v1/lookup/firewall/{id}/aliases | OPNsense 別名 → 成員OPNsense alias → members |
/api/v1/lookup/pfsense/{id}/rules | pfSense tracker → 說明pfSense tracker → description |
/api/v1/lookup/pfsense/{id}/aliases | pfSense 別名 → 成員pfSense alias → members |
/api/v1/lookup/proxmox/vms | 全部叢集:vmid → VM 名稱All clusters: vmid → VM name |
/api/v1/lookup/proxmox/{cluster_id}/vms | 單一叢集:vmid → VM 名稱One cluster: vmid → VM name |
curl "https://ipam.example.com/api/v1/lookup/hostnames?token=<dsv-token>"
"192.0.2.10","web01"
"192.0.2.11","db01"
在 Graylog 的 DSV 配接器裡,Key column = 0、Value column = 1(欄位索引從 0 起算)。防火牆相關端點要先在該台整合設定裡勾選「提供防火牆 DSV」才會有資料。 In Graylog's DSV adapter set Key column = 0 and Value column = 1 (indices are 0-based). The firewall endpoints only return data once "expose firewall DSV" is enabled on that instance.
13MCP(給 LLM 用) (for LLMs)
jt-ipam 內建 MCP(Model Context Protocol)伺服器,讓 LLM 用自然語言查 IPAM。走 JSON-RPC 2.0: jt-ipam ships an MCP (Model Context Protocol) server so an LLM can query the IPAM in natural language, over JSON-RPC 2.0:
- Streamable HTTP:
POST /api/mcp。initialize的回應會帶Mcp-Session-Id標頭。支援initialize、ping、tools/list、tools/call。 Streamable HTTP:POST /api/mcp. Theinitializeresponse carries anMcp-Session-Idheader. Supportsinitialize,ping,tools/listandtools/call. - stdio(本機用,例如 Claude Desktop):
python -m app.mcp.stdio_server,權杖放環境變數JT_IPAM_MCP_TOKEN。 stdio (local, e.g. Claude Desktop):python -m app.mcp.stdio_server, with the token inJT_IPAM_MCP_TOKEN.
認證用 X-Auth-Token 或 Authorization: Bearer,可以是:
Authentication uses X-Auth-Token or Authorization: Bearer, with either:
- 對外唯讀 MCP 金鑰(
jtmcp_…,admin 在「管理 → LLM/AI」產生並輪替)—— 只看得到唯讀工具,異動類工具會被隱藏並擋下。要先啟用「對外 MCP」才會生效。 A read-only external MCP key (jtmcp_…, generated and rotated by an admin under Admin → LLM/AI) — read-only tools only; mutating tools are hidden and blocked. External MCP must be enabled first. - 一般 API 權杖(
jt_…)—— 依該權杖擁有者的權限。若這把權杖是唯讀 scope,MCP 同樣只給唯讀工具。 A regular API token (jt_…) — scoped to its owner's permissions. If the token is read-only, MCP likewise exposes only read-only tools.
curl -X POST https://ipam.example.com/api/mcp \
-H "X-Auth-Token: jtmcp_xxxxxxxx" -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
14代理協定Agent protocols
掃描代理與憑證派送代理有自己的通道,用各自獨立的金鑰(X-Agent-Key 標頭,建立代理時產生、只存雜湊),不是 API 權杖。這些端點是給代理程式用的,一般整合不需要碰。
The scan agent and certificate-distribution agent have their own channel, authenticated by per-agent keys (the X-Agent-Key header, issued when the agent is created and stored only as a hash) rather than API tokens. These endpoints are for the agents themselves; normal integrations don't need them.
| 路徑Path | 用途Purpose |
|---|---|
GET /api/v1/scan-agents/poll | 代理取得要掃的子網路與方法Agent fetches the subnets and probes to run |
POST /api/v1/scan-agents/report | 代理回報存活 IP、MAC、主機名稱Agent reports live IPs, MACs and hostnames |
GET /api/v1/cert-agents/check | 代理比對指紋與到期日Agent compares fingerprints and expiry |
GET /api/v1/cert-agents/bundle/raw | 代理取憑證內容(多種格式)Agent fetches certificate material (several formats) |
POST /api/v1/cert-agents/report | 代理回報派送結果Agent reports deployment results |
GET /api/v1/cert-agents/agent.shGET /api/v1/cert-agents/agent.ps1 | 代理程式本體(Linux / Windows),公開可取、無密鑰;代理據此自我更新The agent itself (Linux / Windows). Public, contains no secrets; agents self-update from it |
bundle/raw?part=pkcs12 可帶 X-Pfx-Password 標頭。帶了就回以該密碼加密、且 Windows 匯得進去的 PKCS#12(PBESv1-SHA1-3DES)—— PBESv1 是 Windows CryptoAPI 全版本都吃的形式;函式庫預設的 PBESv2/AES-256 失敗時訊息是誤導的「密碼不正確」。不帶標頭時行為不變(不加密)。Windows 代理每次執行自產一組隨機密碼且只留在記憶體,私鑰不會為了匯入而寫到磁碟。
bundle/raw?part=pkcs12 accepts an X-Pfx-Password header. With it you get a PKCS#12 encrypted with that password using the encryption Windows can actually import (PBESv1-SHA1-3DES) — PBESv1 is the form every version of the Windows CryptoAPI accepts; the library default, PBESv2/AES-256, fails with a misleading "the password is incorrect". Without the header the behaviour is unchanged (unencrypted). The Windows agent generates a random password per run and keeps it in memory, so the private key is never written to disk on the way in.
X-Agent-Key 等同於它 scope 內所有憑證的私鑰,請當成最高敏感憑證保管。
The certificate bundle endpoint decrypts and returns private keys (HTTPS-only, audited on every fetch). That X-Agent-Key is equivalent to the private keys of every certificate in its scope — treat it as a top-tier secret.
另有兩支完全免認證的健康檢查端點,給負載平衡器用:GET /healthz(存活)與 GET /readyz(就緒,DB/Redis 不通時回 503)。
Two entirely unauthenticated health endpoints exist for load balancers: GET /healthz (liveness) and GET /readyz (readiness, returning 503 when the DB or Redis is unreachable).
15速率限制與 CORSRate limits & CORS
依來源 IP 分桶限流,超過回 429 並帶 Retry-After(秒)。預設值(可在後端設定調整):
Rate limits are bucketed per source IP; exceeding one returns 429 with Retry-After (seconds). Defaults (configurable in the backend):
| 分桶Bucket | 預設Default | 適用Applies to |
|---|---|---|
api_token | 600 / min | 用 API 權杖呼叫API-token calls |
default | 100 / min | 一般請求General requests |
auth | 10 / min | 登入等認證端點Login and other auth endpoints |
ai | 20 / min | LLM 推論(昂貴,較嚴格)LLM inference (expensive, tighter) |
CORS:正式環境只允許明確列出的 HTTPS 來源(不接受 *、不接受 HTTP)。因此瀏覽器端的跨網域呼叫預設不會通 —— 第三方整合請走伺服器對伺服器。
CORS: in production only explicitly-listed HTTPS origins are allowed (no *, no HTTP). So cross-origin browser calls will not work by default — do third-party integrations server-to-server.
16OpenAPI
後端是 FastAPI,會自動產生 OpenAPI 規格。但正式環境(APP_ENV=production)一律關閉 /docs、/redoc 與 /openapi.json,避免對外洩漏完整攻擊面。
The backend is FastAPI and generates an OpenAPI spec automatically. However /docs, /redoc and /openapi.json are disabled in production (APP_ENV=production) so the full attack surface isn't published.
要拿完整的機器可讀規格(含每個端點的全部欄位),在非正式環境的實例上開一台即可: To get the complete machine-readable spec (every field of every endpoint), run a non-production instance:
APP_ENV=development uvicorn app.main:app
curl http://127.0.0.1:8000/openapi.json > jt-ipam-openapi.json
拿到 openapi.json 之後可以直接餵給 openapi-generator 產出各語言的 client。
Feed that openapi.json to openapi-generator to produce a client in your language of choice.