Cómo exportar el System Log de Okta (API, CSV, SIEM)
Exporta el System Log de Okta para una investigación: CSV de la Admin Console, /api/v1/logs con la paginación correcta, Log Streaming, SIEM y trampas a evitar.
TL;DR. Para una investigación, descarga toda la organización durante los 90 días de retención con GET /api/v1/logs, una ventana acotada since/until y limit=1000, y sigue la cabecera Link: rel="next" hasta que desaparezca. Nunca pagines moviendo since a mano. Usa el CSV de la Admin Console solo para un vistazo rápido, y los datos de SIEM o Log Streaming cuando necesites más de 90 días. Conserva el JSON original: todos los demás formatos pierden campos.
En la exportación es donde más investigaciones de Okta se tuercen sin que nadie lo note. No porque sea difícil, sino porque el atajo evidente (buscar al usuario sospechoso, pulsar descargar) produce un fichero que parece completo y no lo es. Este artículo es la versión larga de la lista de la página principal de la herramienta.
Qué estás exportando
El System Log de Okta es un flujo de objetos LogEvent. Cada uno tiene un eventType, un actor, un array target, un client (IP, user agent, geolocalización), un securityContext (ASN, organización del AS, ISP, indicador de proxy), un authenticationContext (con el identificador de sesión), un outcome, un debugContext.debugData y un uuid único. El esquema está documentado en la referencia de la API del System Log.
Dos propiedades de los datos determinan todo lo que sigue:
- La retención es de 90 días. Okta indica que no devuelve datos de más de 90 días (guía de consultas del System Log). Si el incidente puede ser más antiguo, solo queda lo que se haya enviado por streaming o recopilado antes.
- Las correlaciones necesitan los eventos de otras personas. Un restablecimiento del helpdesk se registra con el agente como actor y tu víctima como objetivo. Una concesión de rol, con el atacante como actor y el nuevo administrador como objetivo. Filtra por un usuario y perderás la mitad de la historia.
Opción 1: la API del System Log (recomendada)
Te da el JSON original, todos los campos y un procedimiento repetible.
Credenciales
Usa un acceso de solo lectura: un token de API creado por un administrador de solo lectura, o una aplicación de servicio OAuth 2.0 con el scope okta.logs.read. Un token de API de Okta tiene los permisos del administrador que lo creó (Okta Help Center: tokens de API), así que no lo crees desde un Super Administrator para esta tarea y revócalo cuando termine la exportación. Durante un incidente activo, asegúrate además de que la cuenta que usas no es una de las que el atacante podría controlar.
Solicitudes acotadas y paginación
La guía de consultas distingue dos tipos de solicitudes:
| Solicitud acotada | Solicitud de polling | |
|---|---|---|
| Parámetros | since y until definidos | sin until, sortOrder=ASCENDING |
| Uso | exportar un periodo fijo | seguir los eventos nuevos de forma continua |
| Fin | la última página no tiene enlace next | siempre devuelve un enlace next |
| Orden | por published | puede venir desordenado |
Para forense quieres una solicitud acotada. La guía es explícita en dos puntos importantes: sigue los enlaces next en lugar de paginar a mano con since y until (puede saltarse o duplicar eventos), y algunos eventos de un rango reciente pueden llegar con retraso. Exporta hasta «ahora menos unos minutos» y vuelve a exportar las últimas horas más tarde si el incidente sigue en curso.
Un bucle de shell mínimo:
url="https://${OKTA_DOMAIN}/api/v1/logs?since=2026-06-15T00:00:00Z&until=2026-09-13T00:00:00Z&limit=1000"
n=0
while [ -n "$url" ]; do
n=$((n+1))
curl -sS -D headers.txt \
-H "Authorization: SSWS ${OKTA_API_TOKEN}" \
-H "Accept: application/json" \
"$url" > "okta-system-log-$(printf %04d $n).json"
url=$(tr -d '\r' < headers.txt | grep -i '^link:.*rel="next"' \
| sed -E 's/^[Ll]ink: <([^>]+)>.*/\1/')
sleep 1 # mantenerse muy por debajo del límite de peticiones
done
gzip okta-system-log-*.json
Cada página es un array JSON. No hace falta fusionarlas: el analizador acepta muchos ficheros a la vez, y también arrays escritos uno tras otro en un mismo fichero. Los eventos se deduplican por uuid, así que las páginas solapadas o una segunda ejecución no causan problemas.
limit llega hasta 1.000 eventos por página. Las consultas están sujetas a límites de peticiones y a un tiempo máximo de 30 segundos por consulta, de modo que una organización muy activa durante 90 días supone muchas páginas; déjalo trabajar.
Filtrar en el servidor: solo para el triaje
La API admite una expresión filter como eventType eq "user.mfa.factor.reset_all" y un parámetro de palabra clave q (guía de consultas). Son útiles para responder una pregunta rápida. Para la exportación de pruebas, no los uses.
Opción 2: CSV de la Admin Console
En la Admin Console, Reports › System Log, fija el periodo, deja la búsqueda vacía y usa Download CSV (Okta Help Center: System Log). No necesita token y es rápido para periodos cortos.
La contrapartida es la fidelidad: un CSV aplana los objetos anidados y no he podido verificar en la documentación pública el conjunto exacto de columnas de la descarga de la consola. El analizador lee CSV cuyas cabeceras son rutas de LogEvent (actor.alternateId, client.ipAddress, target[0].displayName, securityContext.asNumber, etc.) o una columna _raw con el JSON original. Si un CSV de la consola da menos hallazgos de los esperados, repite la exportación por la API antes de sacar conclusiones.
Opción 3: Log Streaming (EventBridge, Splunk Cloud)
Okta puede enviar los eventos del System Log casi en tiempo real a Amazon EventBridge o Splunk Cloud; un super admin lo configura en Reports › Log Streaming (Okta Help Center: log streaming). Un stream solo reenvía los eventos a partir de su creación: es una estrategia de retención, no una herramienta de recuperación.
Si ya existe un stream, exporta el periodo desde su destino:
- Los archivos de EventBridge (S3, CloudWatch Logs) guardan cada LogEvent en el campo
detaildel sobre de EventBridge. El JSON o JSON Lines, comprimido con gzip o no, se puede soltar tal cual. - Splunk: busca el source type de Okta y exporta los resultados como JSON o CSV. El campo
_rawcontiene el evento original y se usa cuando está presente; los sobresresultse desempaquetan.
Opción 4: otros SIEM
La regla es la misma en todas partes: exporta los eventos originales con los nombres de campo originales.
- Elastic: los documentos se extraen de
_sourceautomáticamente. - JSON Lines genérico, con un LogEvent por línea, funciona directamente, igual que las líneas con prefijo syslog que terminan con el evento JSON.
- Microsoft Sentinel: la tabla personalizada clásica
Okta_CLaplana los campos en columnas con sufijo comoactor_alternateId_s; el analizador todavía no las mapea. Si tienes el JSON original, exporta ese.
Lista de comprobación previa
Antes de entregar la exportación a nadie, o al analizador:
- El periodo cubre al menos varios días antes del primer evento sospechoso (las líneas base necesitan historial).
- No se aplicó ningún filtro ni búsqueda.
- Las marcas
publishedprimera y última coinciden con la ventana solicitada. - Los ficheros se guardan sin modificar, con sus hashes, donde el atacante no pueda alcanzarlos.
- El token o la aplicación de servicio usados para exportar están revocados o desactivados.
El siguiente paso es analizar la exportación. Si todavía no sabes qué buscar, empieza por la guía de investigación de un compromiso en Okta.
Lecturas recomendadas
- Okta Developer: guía de consultas del System Log (solicitudes acotadas y de polling, filtros, retención)
- Okta Developer: referencia de la API del System Log
- Okta Help Center: log streaming
- Okta Help Center: gestión de tokens de API