Gobierne Zedmos desde donde sea.
Cada capacidad de Zedmos que expone la interfaz de la consola es un punto final REST. Esta guía cubre las dos formas seguras de que un sistema remoto llegue a ellas —una clave de API directa o el proxy WebSocket de zedmos-console— además de una referencia completa y categorizada de puntos finales.
API directa o proxy WebSocket
Ambas vías terminan en los mismos controladores /api/zedmos/*: solo cambian el transporte y las credenciales. Elija una por integración.
- Expone
- El propio cortafuegos OPNsense (su servidor web). En pfSense, la protección equivalente solo admite la interfaz de bucle: use el proxy WebSocket.
- Transporte
- HTTPS directo a la interfaz de administración del cortafuegos.
- Credencial
- Clave y secreto de API de OPNsense (autenticación HTTP Basic). pfSense usa una clave y un secreto generados localmente, aceptados solo en la interfaz de bucle.
- Ámbito
- Una sola ACL de OPNsense —page-services-zedmos— controla todos los puntos finales (lectura Y escritura). No hay un ámbito de solo lectura incorporado. En pfSense la barrera equivalente es el privilegio de la ACL de Zedmos.
- Ideal para
- Un partner en un segmento de confianza o una VPN entre sedes, o uno al que pueda restringir por IP.
- Expone
- El hub en la nube de Zedmos (zedmos-backend). El cortafuegos llama hacia él.
- Transporte
- El cortafuegos abre un túnel wss:// saliente hacia el hub; el partner llama a la API REST del hub.
- Credencial
- Token de sesión de la consola del hub (Bearer). El cortafuegos se inscribe con tenant_id, node_id y agent_secret (HMAC).
- Ámbito
- Lista de permitidos por ruta en el agente, MÁS la ACL de la clave de API local, MÁS el aislamiento por inquilino del hub.
- Ideal para
- Administración SaaS o multiinquilino, cortafuegos tras NAT, o cualquier cosa que no deba exponer hacia dentro.
Inicio rápido
En OPNsense, la API directa usa una clave y un secreto de API de OPNsense mediante HTTP Basic. Las llamadas sin autenticar reciben un HTTP 302 (redirección al inicio de sesión), no un 401. Las llamadas con clave de API están exentas de CSRF. En pfSense, la protección local de la API solo admite la interfaz de bucle, así que las integraciones remotas pasan por el proxy WebSocket.
# OPNsense only - on pfSense use the WebSocket-proxy example below
# 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}}La forma más segura de exponer esto
Para una empresa externa que no controla del todo, prefiera el proxy WebSocket: sin puerto entrante, con lista de permitidos por ruta, aislamiento por inquilino y revocación central. Use la API directa solo en un segmento de confianza o una VPN, y siempre endurecida.
Una sola ACL lo controla todo
page-services-zedmos cubre todos los puntos finales /api/zedmos/*, lectura y escritura. No hay un privilegio de Zedmos por punto final ni de solo lectura. Acote a un partner con reglas de red o con la lista de permitidos del proxy WS.
Las claves de API se saltan el CSRF
Las llamadas con clave de API están exentas del token anti-CSRF (solo lo necesitan las sesiones de navegador en métodos distintos de GET). Algunos puntos finales también modifican en GET sin protección de método: es aceptable con claves, pero limite los métodos en un proxy inverso si los expone.
Siempre HTTPS, siempre restringido por IP
La API escucha en todas las interfaces (*:80 en el laboratorio). Para uso remoto, pase la interfaz web a HTTPS con un certificado válido y restrinja el puerto de administración por regla de cortafuegos a las IP de origen del partner.
Prefiera el proxy WS para terceros
No abre ningún puerto entrante, restringe exactamente qué rutas puede llamar el partner (lista de permitidos), aísla inquilinos y es revocable de forma central (con una lápida firmada). Es el canal recomendado para integradores no confiables.
Recomendación
Proxy WS para terceros no confiables. API directa solo tras HTTPS y una regla de cortafuegos en el puerto de administración limitada a las IP de origen del partner, con un usuario de servicio dedicado que solo tenga page-services-zedmos.
El esquema de policies.json
Cada clave que el partner puede leer con /policies/get y escribir con /policies/groupsave o /policies/save. Esquema 1.1.0. Los valores permitidos y los valores por defecto proceden de la documentación integrada en el propio documento.
Estructura del documento
eval: orden de evaluación
evalgroups[]: el objeto de grupo de políticas
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[].webAI Security & DLP
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.
App 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: valores por defecto, catálogos y ajustes del motor
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"] }
]
}Todas las categorías
Agrupadas exactamente como en la consola: primero Policies, después Settings, Notifications, Reports, Live y el resto. Las rutas son relativas a la base de cada categoría.
/api/zedmos/policiesLa superficie principal. Gobierna policies.json: grupos, valores globales, catálogo de seguridad, categorías de aplicaciones, preajustes de DLP e inteligencia de amenazas.
/api/zedmos/settingsLa superficie más grande (unas 62 acciones): TLS/CA, interfaces y procesos de trabajo, IDS/ETA/TI, writerd y almacenamiento, AD e identidad, consola en la nube, reconocimiento de dispositivos y control de tráfico.
/api/zedmos/notificationsCanal de alertas y despachador. El único controlador con su propia barrera de autorización (canModify: usuario de la sesión, o interfaz de bucle / mismo host). La configuración está en notifications.json.
/api/zedmos/reportsPuntos finales de gráficos de solo lectura sobre la base de datos de flujos. Todos fuerzan POST en dispatch() para que la interfaz pueda pedirlos por XHR-GET; con una clave de API puede llamar por cualquiera de los dos métodos. Parámetros habituales: hours(1-168), since/until(ms), mode(session/packet/volume). La mayoría devuelve {labels, values}.
/api/zedmos/liveCanales casi en tiempo real. Consúltelos con un cursor since (la interfaz usa sondeo: en la máquina no hay WebSocket ni SSE). Parámetros habituales: hours(6), since(ms), limit(1000, 10-2000), además de los filtros inteligentes (filters_<ep>, sf_*).
/api/zedmos/dashboardIndicadores agregados, telemetría del sistema (CPU, temperatura, disco), estado de las funciones y control de servicios y actualizaciones.
/api/zedmos/deviceInventario de dispositivos y su ciclo de vida. Usa argumentos posicionales en la ruta para las acciones con <id>, por ejemplo /device/trust/42.
/api/zedmosOtros controladores, resumidos. Cada uno sigue la misma convención /api/zedmos/<slug>/<command> y la misma autenticación.
La vía B, en detalle
El cortafuegos llama hacia el hub; el partner llama a la API REST del hub, que retransmite la llamada por el socket. El agente aplica una lista de permitidos por petición antes de tocar la API local.
API REST del hub: lo que llama el partner
Preajustes de listas de permitidos (el límite por petición)
core-read-onlyUnos 364 puntos finales GET de solo lectura en 24 módulos. Valor por defecto seguro.firewall-adminfirewall/* completo en lectura y escritura, más core/diag/interfaces en solo lectura.network-admininterfaces/*, routes/* y routing/* completos, más core/diag en solo lectura.vpn-adminipsec/*, openvpn/* y wireguard/* completos (en disco; se eligen con una lista propia).ids-monitorids/* completo más core/diag en solo lectura (en disco; se elige con una lista propia).full-adminTodo, todos los módulos. «Equivalente a saltarse la protección». No lo entregue a partners.Ninguno de los preajustes incluidos abarca /api/zedmos/*. Para una integración de políticas, use una lista de permitidos propia:
# 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/*Protocolo de mensajes (referencia)
Hub → agente: {"type":"http","requestId","method","url","body","timeoutMs"}\nAgente → hub: {"type":"httpResponse","requestId","status","body","error"}\nSaludo inicial: el hub envía un nonce de desafío; el agente responde con HMAC-SHA256(agent_secret, "tenant|node|ts|nonce"); el hub responde hello_ack. La revocación se hace con una lápida firmada.Referencia completa en prosa con todos los puntos finales y parámetros: docs/ZEDMOS_API_REFERENCE.md en el repositorio.