Steuern Sie Zedmos von überall.
Jede Zedmos-Funktion der Konsolen-UI ist ein REST-Endpunkt. Dieser Leitfaden zeigt die zwei sicheren Wege, sie aus der Ferne zu erreichen — ein direkter API-Key oder der zedmos-console WebSocket-Proxy — samt vollständiger, kategorisierter Endpunkt-Referenz.
Direkte API oder der WebSocket-Proxy
Beide Wege erreichen letztlich dieselben /api/zedmos/*-Controller — nur Transport und Zugangsdaten unterscheiden sich. Wählen Sie einen pro Integration.
- Bereitsteller
- Die OPNsense-Firewall selbst (ihr Webserver).
- Transport
- HTTPS direkt zur Management-Schnittstelle der Firewall.
- Zugangsdaten
- OPNsense-API-Key + Secret (HTTP-Basic-Auth).
- Begrenzung
- Eine einzige OPNsense-ACL — page-services-zedmos — schützt jeden Endpunkt (Lesen UND Schreiben). Kein eingebauter Nur-Lese-Bereich.
- Geeignet für
- Ein Partner in einem vertrauenswürdigen Segment / Site-to-Site-VPN oder per IP einschränkbar.
- Bereitsteller
- Der Zedmos-Cloud-Hub (zedmos-backend). Die Firewall wählt sich nach außen ein.
- Transport
- Firewall öffnet einen ausgehenden wss://-Tunnel zum Hub; der Partner ruft die REST-API des Hubs auf.
- Zugangsdaten
- Hub-Konsolen-Sitzungstoken (Bearer). Firewall ist mit tenant_id + node_id + agent_secret (HMAC) registriert.
- Begrenzung
- Pfad-Allowlist-Preset am Agenten, PLUS lokale API-Key-ACL, PLUS Mandanten-Isolation des Hubs.
- Geeignet für
- SaaS / Multi-Tenant-Verwaltung, Firewalls hinter NAT oder alles, was nicht eingehend exponiert werden darf.
Schnellstart
Die direkte API nutzt einen OPNsense-API-Key + Secret über HTTP-Basic. Nicht authentifizierte Aufrufe erhalten HTTP 302 (Weiterleitung zum Login), nicht 401. API-Key-Aufrufe sind von CSRF ausgenommen.
# 1) Create an API key in OPNsense: System > Access > Users > API keys
# The user must hold the "Services: Zedmos" privilege (page-services-zedmos).
KEY='....' # OPNsense API key
SECRET='....' # OPNsense API secret
# Read — list policy groups
curl -s -u "$KEY:$SECRET" \
https://fw.example.com/api/zedmos/policies/groups
# -> {"groups":[{"name":"Default","status":true}, ...]}
# Write — block a domain globally (POST, JSON body)
curl -s -u "$KEY:$SECRET" -H 'Content-Type: application/json' \
-d '{"type":"host","value":"badsite.com","global":true}' \
https://fw.example.com/api/zedmos/policies/block
# -> {"status":"ok"}const base = "https://fw.example.com";
const auth =
"Basic " + Buffer.from(`${process.env.ZED_KEY}:${process.env.ZED_SECRET}`).toString("base64");
async function zed(path, { method = "GET", body } = {}) {
const r = await fetch(`${base}/api/zedmos${path}`, {
method,
headers: { Authorization: auth, ...(body ? { "Content-Type": "application/json" } : {}) },
body: body ? JSON.stringify(body) : undefined,
});
if (r.status === 302) throw new Error("auth failed (redirect to login)");
return r.json();
}
const groups = await zed("/policies/groups");
await zed("/policies/block", {
method: "POST",
body: { type: "category", value: "AdultContent", group: "Strict" },
});# The partner never talks to the firewall directly — it calls the hub,
# which routes the call down the firewall's outbound socket.
curl -s -X POST https://www.zedmos.com/api/agent/proxy/http \
-H "Authorization: Bearer $CONSOLE_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"tenant_id": "69fb...",
"node_id": "6a0d...",
"method": "GET",
"url": "/api/zedmos/policies/groups"
}'
# -> {"status":"ok","response":{"status":200,"body":"{\"groups\":[...]}","error":null}}Der sicherste Weg, dies bereitzustellen
Für ein externes Unternehmen, das Sie nicht vollständig kontrollieren, bevorzugen Sie den WebSocket-Proxy: kein eingehender Port, Pfad-Allowlist, Mandanten-Isolation, zentraler Widerruf. Die direkte API nur in einem vertrauenswürdigen Segment / VPN und stets gehärtet.
Eine ACL schützt alles
page-services-zedmos deckt jeden /api/zedmos/*-Endpunkt ab, lesend und schreibend. Es gibt kein endpunktbezogenes oder reines Lese-Recht. Schränken Sie einen Partner stattdessen per Netzwerkregeln oder WS-Proxy-Allowlist ein.
API-Keys umgehen CSRF
API-Key-Aufrufe sind vom Anti-CSRF-Token ausgenommen (nur Browser-Sitzungen brauchen es bei Nicht-GET). Manche Endpunkte verändern Zustand sogar per GET ohne Methoden-Guard — für Keys unkritisch, aber begrenzen Sie Methoden an einem Reverse-Proxy, wenn Sie sie exponieren.
Immer HTTPS, immer IP-beschränkt
Die API lauscht auf allen Schnittstellen (*:80 im Labor). Für den Fernzugriff stellen Sie die WebGUI auf HTTPS mit gültigem Zertifikat um und beschränken den Management-Port per Firewall-Regel auf die Quell-IPs des Partners.
Für Dritte den WS-Proxy bevorzugen
Er öffnet keinen eingehenden Port, beschränkt exakt die aufrufbaren Pfade (Allowlist), isoliert Mandanten und ist zentral widerrufbar (signierte Tombstone). Der empfohlene Kanal für nicht vertrauenswürdige Integratoren.
Empfehlung
WS-Proxy für nicht vertrauenswürdige Dritte. Direkte API nur hinter HTTPS + einer Firewall-Regel für den Management-Port, beschränkt auf die Quell-IPs des Partners, mit einem dedizierten Service-Benutzer, der nur page-services-zedmos besitzt.
Das policies.json-Schema
Jeder Schlüssel, den der Partner über /policies/get lesen und über /policies/groupsave bzw. /policies/save schreiben kann. Schema 1.1.0. Erlaubte Werte und Defaults stammen aus der eingebauten Doku des Dokuments.
Dokumentstruktur
eval — Auswertungsreihenfolge
evalgroups[] — das Policy-Gruppen-Objekt
Identity
groups[]Selectors — who the group applies to
groups[].selectorsA flow joins this group when its selectors match. Empty arrays = no constraint on that axis.
Overrides
groups[].overridesExclusions
groups[].exclusionsAllow-list overrides that exempt matching traffic from this group's blocks.
Security catalogs (threat categories)
groups[].securityEach boolean enables blocking of one threat-intel catalog. basic_mode/advanced_mode are convenience presets; the `essential{}` and `advanced{}` objects mirror the flat booleans.
Application control (L7 app-ID)
groups[].appsEncrypted-transport control
groups[].transportFirst-install default: all 'allow'. Switch to 'block' to enforce.
TLS inspection (MITM)
groups[].tlsNetwork (L3/L4) blocks
groups[].networkHard early-drops via fast-reject before rules[] runs. Use a rule with is_exception+action:allow to punch a hole.
Web filtering
groups[].webDLP & AI Gateway
groups[].web.dlpPer-group only — globals.web.dlp is a TEMPLATE the engine ignores. First-install default: OFF.
File / AV scanning
groups[].file.scanDNS control
groups[].dnsETA · Identity · Geo · Risk · TI · IDS
groups[].{eta,identity,geo,risk,ti,ids}Action handlers
groups[].actionsConfigured at group level; a rule references them via its `action`. Most fire only on a DROP-class decision (pair with action:drop). Placeholders $src, $dst, $rule_id.
SD-WAN routing
groups[].routingRules (ordered, fine-grained)
groups[].rules[]Optional per-group ordered rule list evaluated after early-drops. Each rule matches on fields and fires one action.
// POST /api/zedmos/policies/groupsave — Content-Type: application/json
// Upsert one group (only the keys you send are changed; rest is preserved).
{
"name": "Strict",
"status": true,
"description": "Locked-down VLAN",
"selectors": { "vlans": [30], "direction": "any" },
"overrides": { "block_all": false, "block_untrusted": true, "schedule": "work-hours" },
"security": { "basic_mode": "high", "malware_virus": true, "phishing": true },
"apps": { "categories_block": ["adultcontent", "gaming"] },
"transport":{ "quic_strategy": "block", "doh_strategy": "block" },
"tls": { "enable_inspection": true, "bump_mode": "force", "min_version": "1.2" },
"dns": { "block_domains": ["coin-hive.com"], "dga": "block", "tunnel": "block" },
"web": { "dlp": { "enable": true, "mode": "regex_only", "action": "block",
"presets": ["cc_luhn","iban","email_pii"] } },
"file": { "scan": { "mode": "block", "action": "block", "engines": ["clamav"] } },
"ids": { "mode": "prevent", "block_max_priority": 2 },
"rules": [
{ "is_exception": true, "action": "allow", "mode": "any",
"dst_domain": ["intranet.corp"], "comment": "always allow intranet" }
]
}globals — Defaults, Kataloge, Engine-Knobs
Engine knob registry
globals.engineOperator-tunable hot-path knobs. Precedence: value here > env DG_* > hardcoded default. Atomic publish on policy reload.
Global catalogs & defaults
globals.{security,ti,quarantine,schedules,exclusions}// POST /api/zedmos/policies/globals — set global blacklists / actions
{
"exclusions": { "domains": ["windowsupdate.com"], "src_cidrs": ["10.0.0.0/8"] },
"ti": { "domain_block": ["evil.example"], "ip_block": ["203.0.113.7"] },
"schedules": [
{ "name": "work-hours", "start": "08:00", "end": "18:00",
"days": ["Mon","Tue","Wed","Thu","Fri"] }
]
}Jede Kategorie
Gruppiert genau wie die Konsole: zuerst Policies, dann Settings, Notifications, Reports, Live und der Rest. Pfade sind relativ zur jeweiligen Kategorie-Basis.
/api/zedmos/policiesDie zentrale Schnittstelle. Steuert policies.json — Gruppen, Globals, Security-Katalog, App-Kategorien, DLP-Presets und Threat-Intel.
/api/zedmos/settingsDie größte Schnittstelle (~62 Aktionen): TLS/CA, Interfaces & Worker, IDS/ETA/TI, writerd & Storage, AD/Identität, Cloud-Konsole, Geräteerkennung und Traffic-Control.
/api/zedmos/notificationsAlarm-Feed + Dispatcher. Der einzige Controller mit eigenem Autorisierungs-Gate (canModify: Sitzungsbenutzer oder Loopback/gleicher Host). Konfig in notifications.json.
/api/zedmos/reportsReine Lese-Chart-Endpunkte über die Flow-DB. Alle erzwingen POST in dispatch(), damit die UI sie per XHR-GET nutzen kann; mit API-Key beide Methoden möglich. Übliche Parameter: hours(1-168), since/until(ms), mode(session/packet/volume). Meist {labels, values}.
/api/zedmos/liveNahezu-Echtzeit-Feeds. Mit since-Cursor pollen (die UI nutzt Polling — kein WebSocket/SSE auf der Box). Übliche Parameter: hours(6), since(ms), limit(1000, 10-2000), plus Smart-Filter (filters_<ep>, sf_*).
/api/zedmos/dashboardAggregierte KPIs, System-Telemetrie (CPU/Temp/Disk), Feature-Status sowie Dienst- / Update-Steuerung.
/api/zedmos/deviceGeräte-Inventar + Lebenszyklus. Nutzt positionsbasierte Pfad-Argumente für <id>-Aktionen, z. B. /device/trust/42.
/api/zedmosWeitere Controller, zusammengefasst. Jeder folgt der gleichen Konvention /api/zedmos/<slug>/<command> und der gleichen Authentifizierung.
Weg B im Detail
Die Firewall wählt sich zum Hub ein; der Partner ruft die REST-API des Hubs auf, die den Aufruf über den Socket weiterreicht. Der Agent erzwingt vor dem lokalen API-Zugriff eine Allowlist pro Anfrage.
Hub-REST-API — was der Partner aufruft
Allowlist-Presets (die Grenze pro Anfrage)
core-read-only~364 reine Lese-GET-Endpunkte über 24 Module. Sicherer Standard.firewall-adminVoll firewall/* + nur-lesend core/diag/interfaces.network-adminVoll interfaces/*, routes/*, routing/* + nur-lesend core/diag.vpn-adminVoll ipsec/*, openvpn/*, wireguard/* (auf Platte; via custom wählbar).ids-monitorVoll ids/* + nur-lesend core/diag (auf Platte; via custom wählbar).full-adminAlles, jedes Modul. "Entspricht Bypass." Nicht an Partner ausliefern.Keines der ausgelieferten Presets enthält /api/zedmos/*. Für eine Policies-Integration nutzen Sie eine eigene Allowlist:
# Custom allowlist for a policies integration (config.json patterns / preset=custom)
/api/zedmos/policies/*
/api/zedmos/settings/*
# optional read-only telemetry
/api/zedmos/dashboard/*
/api/zedmos/live/*
/api/zedmos/reports/*Nachrichtenprotokoll (Referenz)
Hub → Agent: {"type":"http","requestId","method","url","body","timeoutMs"}
Agent → Hub: {"type":"httpResponse","requestId","status","body","error"}
Handshake: Hub sendet eine Challenge-Nonce; Agent antwortet mit HMAC-SHA256(agent_secret, "tenant|node|ts|nonce"); Hub antwortet hello_ack. Widerruf per signierter Tombstone.Vollständige Referenz mit jedem Endpunkt und Parameter: docs/ZEDMOS_API_REFERENCE.md im Repository.