Skip to content

Latest commit

 

History

History
452 lines (356 loc) · 11.9 KB

File metadata and controls

452 lines (356 loc) · 11.9 KB

API Reference

Base URL: http://<host>:8000
Auth: cabecera X-API-Key: <API_KEY> en endpoints protegidos.
Swagger interactivo: http://<host>:8000/docs (solo con DEBUG=true).


Resumen de endpoints

Método Ruta Auth Descripción
GET /feed/ip/active No* IPs/CIDRs activos — firewall consumable
GET /feed/ip/permanent No* Solo IPs/CIDRs permanentes
GET /feed/ip/temporary No* Solo IPs/CIDRs temporales no expirados
GET /feed/domain/active No* Dominios activos — firewall consumable
GET /feed/domain/permanent No* Solo dominios permanentes
GET /feed/domain/temporary No* Solo dominios temporales no expirados
GET /api/feed/lookup No / Sí Consulta de un elemento (ver modos)
GET /feed/history Historial de reincidencias
GET /api/stats Estadísticas del servicio
POST /api/feed Añadir/actualizar un elemento
POST /api/feed/bulk Importar hasta 500 elementos
POST /api/feed/import Descargar feed remoto desde URL
DELETE /api/feed Eliminar un elemento
GET /api/whitelist Listar entradas de la whitelist
POST /api/whitelist Añadir a la whitelist (pisa blacklist)
DELETE /api/whitelist Eliminar de la whitelist
GET /health No Estado del servicio

* ?detail=true requiere X-API-Key.


Feeds de texto plano

Devuelven text/plain, un elemento por línea.
Compatibles con cualquier firewall que soporte External Block Lists HTTP: FortiGate, Cisco FTD/ASA, MikroTik, pfSense, OPNsense, Squid, nginx y cualquier firewall con soporte de listas HTTP.

GET /feed/ip/active

IPs/CIDRs activos: permanentes + temporales no expirados.

1.2.3.4
10.0.0.0/8
185.220.101.45

GET /feed/ip/permanent

Solo IPs/CIDRs con entry_type = permanent.

GET /feed/ip/temporary

Solo IPs/CIDRs temporales cuya expiración no ha llegado.

GET /feed/domain/active

Dominios activos: permanentes + temporales no expirados.

c2.badactor.net
malware.example.com

GET /feed/domain/permanent

GET /feed/domain/temporary


Modo detail (?detail=true)

Todos los endpoints de feed aceptan ?detail=true. Requiere X-API-Key.
Devuelve application/json con source y comment por entrada.
El plain text sin parámetro no cambia — los firewalls no se ven afectados.

curl "http://localhost:8000/feed/ip/active?detail=true" \
  -H "X-API-Key: $API_KEY"
[
  {
    "element": "1.2.3.4",
    "data_type": "ip",
    "entry_type": "permanent",
    "source": "wazuh-ar",
    "comment": "Incidente #42 — brute force SSH",
    "expires_at": null
  },
  {
    "element": "5.6.7.8",
    "data_type": "ip",
    "entry_type": "temporary",
    "source": "feodo",
    "comment": "Feodo Tracker C2 blocklist",
    "expires_at": "2026-06-03T10:00:00Z"
  }
]

GET /api/feed/lookup

Consulta el estado de un elemento. Dos modos según autenticación.

Sin API key — modo público

Devuelve solo si el elemento está actualmente bloqueado. Una sola query, sin exponer intel interna.

curl "http://localhost:8000/api/feed/lookup?element=1.2.3.4"
{"element": "1.2.3.4", "blocked": true}

Con API key — modo completo

Devuelve estado completo del feed + historial de reincidencias.

curl "http://localhost:8000/api/feed/lookup?element=1.2.3.4" \
  -H "X-API-Key: $API_KEY"
{
  "element": "1.2.3.4",
  "found": true,
  "feed": {
    "data_type": "ip",
    "entry_type": "permanent",
    "source": "wazuh-ar",
    "comment": "Incidente #42 — brute force SSH",
    "expires_at": null,
    "created_at": "2026-06-02T09:00:00Z",
    "active": true
  },
  "history": {
    "occurrences_count": 7,
    "last_seen": "2026-06-02T14:30:00Z"
  }
}

Elemento no registrado:

{"element": "8.8.8.8", "found": false, "feed": null, "history": null}

GET /feed/history

Historial completo de reincidencias, ordenado por ocurrencias descendente.

curl http://localhost:8000/feed/history \
  -H "X-API-Key: $API_KEY"
{
  "total": 42,
  "items": [
    {"element": "1.2.3.4", "data_type": "ip", "occurrences_count": 12, "last_seen": "2026-06-02T09:15:30Z"},
    {"element": "evil.com", "data_type": "domain", "occurrences_count": 7,  "last_seen": "2026-06-02T08:00:00Z"}
  ]
}

GET /api/stats

Estadísticas del servicio y configuración activa.

curl http://localhost:8000/api/stats \
  -H "X-API-Key: $API_KEY"
{
  "feed": {
    "ip":     {"permanent": 42, "temporary_active": 7,  "temporary_expired": 3},
    "cidr":   {"permanent": 5,  "temporary_active": 0,  "temporary_expired": 1},
    "domain": {"permanent": 15, "temporary_active": 2,  "temporary_expired": 0}
  },
  "history": {
    "total_unique_elements": 74,
    "total_occurrences": 312
  },
  "config": {
    "threshold_promotion": 5,
    "promotion_enabled": true
  }
}

POST /api/feed

Añade o actualiza un elemento. Ejecuta historial y promoción automática.

Campo Tipo Valores Notas
element string IP, CIDR o dominio Validado según data_type. Máx. 253 chars
data_type string "ip" | "cidr" | "domain"
entry_type string "permanent" | "temporary"
duration_seconds int 1 – 31 536 000 Requerido si temporary
source string cualquier texto Default: "manual". Máx. 64 chars
comment string | null texto libre Opcional. Máx. 512 chars
curl -X POST http://localhost:8000/api/feed \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "element": "1.2.3.4",
    "data_type": "ip",
    "entry_type": "temporary",
    "duration_seconds": 3600,
    "source": "wazuh-ar",
    "comment": "Incidente #42 — brute force SSH"
  }'
{
  "element": "1.2.3.4",
  "data_type": "ip",
  "entry_type": "temporary",
  "source": "wazuh-ar",
  "comment": "Incidente #42 — brute force SSH",
  "occurrences_count": 3,
  "promoted_to_permanent": false,
  "message": null
}

Al alcanzar el umbral:

{
  "entry_type": "permanent",
  "occurrences_count": 5,
  "promoted_to_permanent": true,
  "message": "Auto-promoted to permanent (threshold=5 occurrences reached)."
}

Los entries permanent nunca se degradan a temporary. Si se re-envían, se actualizan source y comment.


POST /api/feed/bulk

Importa hasta 500 elementos por petición. Los fallos individuales no abortan el lote.

curl -X POST http://localhost:8000/api/feed/bulk \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      {"element": "1.1.1.1", "data_type": "ip", "entry_type": "permanent", "source": "manual"},
      {"element": "2.2.2.2", "data_type": "ip", "entry_type": "temporary", "duration_seconds": 7200, "source": "n8n"},
      {"element": "bad.example.com", "data_type": "domain", "entry_type": "permanent", "comment": "Phishing confirmado"}
    ]
  }'
{
  "processed": 3,
  "failed": 0,
  "results": [
    {"element": "1.1.1.1", "data_type": "ip", "entry_type": "permanent", "source": "manual", "occurrences_count": 1, "promoted_to_permanent": false, "error": null},
    ...
  ]
}

POST /api/feed/import

Descarga una URL de threat feed en texto plano y la importa masivamente.
INSERT OR IGNORE — los elementos ya existentes no se modifican.
No incrementa contadores de historial (imports masivos no deben inflar reputación).

Campo Tipo Notas
url string URL del feed. Máx. 2048 chars
data_type string "ip" | "domain"
entry_type string Default: "permanent"
duration_seconds int Requerido si temporary
source string Etiqueta de origen. Requerido
comment string | null Nota para todas las entradas importadas
# Feodo Tracker — C2 botnet IPs (abuse.ch)
curl -X POST http://localhost:8000/api/feed/import \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://feodotracker.abuse.ch/downloads/ipblocklist.txt",
    "data_type": "ip",
    "entry_type": "permanent",
    "source": "feodo",
    "comment": "Feodo Tracker C2 blocklist"
  }'
{
  "url": "https://feodotracker.abuse.ch/downloads/ipblocklist.txt",
  "source": "feodo",
  "inserted": 287,
  "skipped_duplicate": 12,
  "skipped_invalid": 3,
  "skipped_whitelist": 2,
  "total_parsed": 302
}

skipped_whitelist — entradas presentes en la whitelist que se ignoraron durante la importación.

Feeds públicos compatibles

Nombre URL data_type
Feodo Tracker (C2 IPs) https://feodotracker.abuse.ch/downloads/ipblocklist.txt ip
Feodo Tracker recommended https://feodotracker.abuse.ch/downloads/ipblocklist_recommended.txt ip
Emerging Threats compromised https://rules.emergingthreats.net/blockrules/compromised-ips.txt ip
Binary Defense Artillery https://www.binarydefense.com/banlist.txt ip
Blocklist.de all https://lists.blocklist.de/lists/all.txt ip
CI Army https://cinsscore.com/list/ci-badguys.txt ip

DELETE /api/feed

Elimina un elemento de la feed activa. El historial se conserva.

curl -X DELETE http://localhost:8000/api/feed \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"element": "1.2.3.4"}'
{"deleted": "1.2.3.4"}

Whitelist — GET /api/whitelist · POST /api/whitelist · DELETE /api/whitelist

La whitelist tiene prioridad absoluta sobre la blacklist. Un elemento whitelisteado nunca entra en el feed, aunque Wazuh dispare un AR sobre él. Además, al añadirlo se elimina de la blacklist si estuviera presente.

Se carga automáticamente al arrancar desde seeds/whitelist/ip.txt y seeds/whitelist/domains.txt antes que cualquier seed de blacklist.

GET /api/whitelist

curl http://localhost:8000/api/whitelist \
  -H "X-API-Key: $API_KEY"
{
  "total": 3,
  "items": [
    {"element": "192.168.0.0/16", "comment": "Red interna cliente", "created_at": "2026-06-04T08:00:00Z"},
    {"element": "10.0.0.0/8",     "comment": null,                  "created_at": "2026-06-04T08:00:00Z"},
    {"element": "empresa.com",    "comment": "Dominio corporativo",  "created_at": "2026-06-04T08:00:00Z"}
  ]
}

POST /api/whitelist

Añade un elemento. Si ya existía, actualiza el comment. Si estaba en la blacklist, lo elimina de allí.

curl -X POST http://localhost:8000/api/whitelist \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"element": "203.0.113.0/24", "comment": "Rango público oficina cliente"}'
{
  "element": "203.0.113.0/24",
  "created": true,
  "message": "Added to whitelist and removed from blacklist if present."
}

DELETE /api/whitelist

curl -X DELETE http://localhost:8000/api/whitelist \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"element": "203.0.113.0/24"}'
{"deleted": "203.0.113.0/24"}

Comportamiento de coincidencia

Intento de bloqueo Whitelist contiene Resultado
192.168.1.50 192.168.0.0/16 Whitelisted (IP dentro del CIDR)
10.5.0.0/24 10.0.0.0/8 Whitelisted (CIDR contenido en CIDR)
empresa.com empresa.com Whitelisted (coincidencia exacta)
1.2.3.4 192.168.0.0/16 No whitelisted — entra en blacklist

La respuesta de POST /api/feed incluye "whitelisted": true cuando el elemento fue ignorado por estar en la whitelist:

{
  "element": "192.168.1.50",
  "whitelisted": true,
  "occurrences_count": 0,
  "promoted_to_permanent": false,
  "message": "Whitelisted — skipped."
}

GET /health

curl http://localhost:8000/health
# {"status": "ok"}