Tutorial técnico: configura alertas de Google Cloud Audit Logs con Pub/Sub, n8n y Slack, incluyendo código JavaScript, confirmaciones ACK, deduplicación y cuarentena.
Guía práctica de Cloud Security Monitoring, SIEM ligero, automatización de alertas y auditoría de infraestructura.
¿Es posible monitorear eventos críticos de Google Cloud automáticamente y recibir alertas en Slack?
Sí. Google Cloud Audit Logs, Cloud Logging, Pub/Sub y n8n permiten construir un sistema automatizado que detecta determinadas operaciones administrativas, las procesa, envía alertas a Slack y registra qué mensajes ya fueron atendidos.
En SEOwmx desarrollamos una arquitectura basada en estos servicios, utilizando componentes nativos de Google Cloud y n8n. El objetivo era evitar depender de una revisión manual constante de los registros de actividad.
El resultado fue un flujo capaz de:
- Detectar cambios en permisos IAM y operaciones administrativas seleccionadas.
- Identificar modificaciones de firewall y acciones sensibles sobre instancias de Compute Engine.
- Enviar información contextual a un canal de Slack.
- Registrar los eventos procesados en una Data Table.
- Reconocer mensajes repetidos para evitar notificaciones redundantes en condiciones normales.
- Separar mensajes desconocidos o inválidos en una cuarentena.
- Confirmar la recepción mediante el mecanismo ACK de Pub/Sub.
- Notificar errores del propio workflow mediante una automatización independiente.
En esta guía explicamos cómo se diseñó la solución, qué código utiliza, los problemas que encontramos y qué precauciones debemos tomar antes de utilizarla en producción.
1. El problema: tener registros de auditoría no equivale a tener monitoreo
Google Cloud genera registros de auditoría que permiten conocer determinadas acciones realizadas sobre los recursos de una infraestructura.
Sin embargo, conservar esos registros no significa que alguien los esté revisando oportunamente.
Una modificación en las políticas de acceso, la eliminación de una máquina virtual o un cambio en una regla de firewall puede necesitar atención inmediata.
En un entorno con múltiples recursos, revisar manualmente Cloud Logging no siempre resulta práctico.
La solución consiste en transformar determinados registros en eventos automatizados, clasificarlos y enviarlos hacia un canal operativo.
Un sistema básico de monitoreo debería responder estas preguntas:
¿Qué ocurrió? La operación administrativa registrada.
¿Quién realizó la operación? La identidad disponible en el registro de auditoría.
¿Sobre qué recurso? El proyecto, instancia, firewall o recurso afectado.
¿Cuándo ocurrió? La marca temporal original.
¿Se notificó correctamente? El resultado del envío y su registro en el sistema.
Estas respuestas constituyen el contexto mínimo para una alerta de seguridad útil.
2. Arquitectura de la solución
La implementación utiliza seis componentes principales:
| Componente | Función |
|---|---|
| Google Cloud Audit Logs | Fuente de eventos administrativos |
| Cloud Logging / Log Router | Filtra y enruta registros |
| Pub/Sub | Transporta los eventos mediante mensajes |
| n8n | Decodifica, clasifica y automatiza |
| Data Tables de n8n | Registra mensajes procesados y cuarentena |
| Slack | Recibe notificaciones operativas |
La arquitectura lógica es:
GOOGLE CLOUD
|
v
Cloud Audit Logs
|
v
Cloud Logging / Log Router
|
v
Pub/Sub Topic
|
v
Pub/Sub Pull Subscription
|
v
n8n - Schedule Trigger
|
v
HTTP Request - Pub/Sub Pull
|
v
Code - Decodificar y clasificar
|
v
IF - ¿Es una alerta crítica?
|
+-- SÍ
| |
| v
| Data Table - Buscar messageId
| |
| v
| IF - ¿Ya procesado?
| |
| +-- SÍ --> ACK duplicado
| |
| +-- NO
| |
| v
| Crear mensaje Slack
| |
| v
| Publicar alerta
| |
| v
| Registrar mensaje
| |
| v
| ACK
|
+-- NO
|
v
IF - ¿Mensaje conocido?
|
+-- SÍ --> ACK sin alertar
|
+-- NO
|
v
Registrar cuarentena
|
v
ACK
Adicionalmente, existe un segundo workflow:
Error del workflow principal
|
v
n8n Error Trigger
|
v
HTTP Request
|
v
Slack - Alerta de fallo del monitoreo
Este enfoque es un SIEM ligero orientado a eventos, no un sustituto completo de una plataforma SIEM empresarial con correlación avanzada, análisis histórico, detección de amenazas y gestión integral de incidentes.
Antes de empezar: requisitos mínimos
- Un proyecto de Google Cloud con Cloud Logging, Pub/Sub y las API necesarias habilitadas.
- Permisos mínimos para crear un sink, un topic y una suscripción Pull.
- Una instalación de n8n accesible por HTTPS y una credencial OAuth2 configurada.
- Un Incoming Webhook de Slack almacenado de manera segura.
- Un entorno de prueba sin datos reales ni cambios de IAM destructivos.
3. Configurar Cloud Audit Logs y Log Router
El primer componente es Google Cloud Logging.
En Google Cloud Console, accedemos a:
Logging → Logs Router → Create Sink
Creamos un sink que enrute registros seleccionados hacia un tema de Pub/Sub.
Para este ejemplo utilizaremos los identificadores ficticios:
Proyecto: seowmx-security-demo
Sink: seowmx-security-alerts
Topic: seowmx-cloud-audit-alerts
La ruta de destino tendría la estructura:
pubsub.googleapis.com/projects/PROJECT_ID/topics/TOPIC_ID
¿Qué eventos conviene monitorear?
Para una primera implementación seleccionamos operaciones administrativas sensibles:
Cambios de IAM. Modificaciones a políticas de permisos que pueden alterar quién tiene acceso a los recursos.
Cambios de firewall. Creación, eliminación o modificación de reglas y políticas de red.
Operaciones sobre máquinas virtuales. Acciones como detener, eliminar o crear instancias de Compute Engine.
El filtro debe adaptarse a los nombres reales de los métodos que aparecen en los registros del proyecto. No conviene asumir que todas las operaciones emplean exactamente el mismo formato de methodName.
También es importante excluir eventos automatizados conocidos cuando no requieren una intervención humana. De lo contrario, pueden saturar Slack con operaciones legítimas de servicios administrados.
Permisos del sink
Cloud Logging necesita autorización para publicar en el topic.
Para ello se identifica el writer identity del sink y se le concede el rol correspondiente sobre Pub/Sub, normalmente roles/pubsub.publisher, aplicando el principio de mínimo privilegio.
Un error frecuente es crear correctamente el sink y el topic, pero olvidar esta autorización.
El resultado es una arquitectura aparentemente completa que no entrega los registros.
4. Crear el topic y la suscripción Pub/Sub
Pub/Sub actúa como intermediario entre Cloud Logging y n8n.
Creamos un topic para recibir los eventos y una suscripción de tipo Pull para que n8n pueda recuperarlos.
Ejemplo:
Topic:
seowmx-cloud-audit-alerts
Subscription:
seowmx-cloud-audit-pull
Una de las decisiones importantes fue configurar un plazo de confirmación —acknowledgment deadline— de 120 segundos.
¿Por qué?
Porque el workflow puede necesitar varias operaciones antes de confirmar un mensaje:
- Descargarlo de Pub/Sub.
- Decodificarlo.
- Consultar la tabla de eventos procesados.
- Publicar la alerta en Slack.
- Registrar el resultado.
- Confirmar el mensaje con ACK.
Si el plazo vence antes de terminar el procesamiento, Pub/Sub puede volver a entregar el evento.
Un plazo más amplio reduce ese riesgo, pero no garantiza por sí mismo procesamiento exactamente una vez.
5. Conectar n8n con Google Cloud mediante OAuth2
En n8n utilizamos un nodo HTTP Request para consumir la API de Pub/Sub.
La autenticación se realiza mediante OAuth2, con una credencial autorizada para acceder a los recursos necesarios.
Uno de los aspectos importantes de la configuración es el callback OAuth2 de n8n. Debe coincidir con la URL autorizada en el cliente OAuth de Google Cloud.
La solicitud de lectura utiliza:
POST https://pubsub.googleapis.com/v1/projects/PROJECT_ID/subscriptions/SUBSCRIPTION_ID:pull
Con el siguiente cuerpo JSON:
{
"maxMessages": 1,
"returnImmediately": true
}
En nuestra primera etapa elegimos procesar un mensaje por ejecución para simplificar la depuración y la asociación de los identificadores de confirmación.
Posteriormente puede aumentarse el número de mensajes, pero eso requiere revisar cómo se procesan y vinculan individualmente los ackId.
¿Qué devuelve Pub/Sub?
Una respuesta con mensajes contiene una colección receivedMessages.
Cada elemento incluye información como:
{
"receivedMessages": [
{
"ackId": "ACK_ID_DE_LA_ENTREGA",
"message": {
"messageId": "MENSAJE_ID",
"publishTime": "FECHA_UTC",
"data": "CONTENIDO_BASE64"
}
}
]
}
El campo data contiene la información codificada en Base64, no un JSON legible directamente.
El messageId sirve para identificar el mensaje; el ackId corresponde a una entrega concreta y debe utilizarse para confirmarla.
No son intercambiables.
6. Decodificar y clasificar los eventos con JavaScript
A continuación utilizamos un nodo Code in JavaScript de n8n.
Su responsabilidad es convertir el mensaje de Pub/Sub en un objeto JavaScript y decidir si corresponde a una alerta.
Este es un ejemplo simplificado y reutilizable, basado en la lógica de la implementación:
const results = [];
for (const item of $input.all()) {
const messages =
item.json.receivedMessages ?? [];
for (const received of messages) {
const { ackId, message } = received;
try {
const decoded = Buffer.from(
message.data,
'base64'
).toString('utf8');
const event = JSON.parse(decoded);
const audit = event.protoPayload ?? {};
const isAudit =
audit['@type'] ===
'type.googleapis.com/google.cloud.audit.AuditLog' &&
Boolean(audit.methodName && audit.serviceName);
const method = String(
audit.methodName ?? ''
);
const service = String(
audit.serviceName ?? ''
);
const user =
audit.authenticationInfo
?.principalEmail ?? null;
const criticalIAM =
/setIamPolicy/i.test(method);
const criticalFirewall =
service === 'compute.googleapis.com' &&
/(?:firewalls|firewallPolicies|networkFirewallPolicies)\./i
.test(method) &&
/\.(?:insert|patch|update|delete|addRule|removeRule|patchRule)$/i
.test(method);
const criticalVM =
service === 'compute.googleapis.com' &&
/(?:^|\.)instances\.(?:insert|delete|stop)$/i
.test(method) &&
!String(user ?? '').endsWith(
'@cloudservices.gserviceaccount.com'
);
const shouldNotify = Boolean(
isAudit &&
(
criticalIAM ||
criticalFirewall ||
criticalVM
)
);
const isTest =
event.source === 'seowmx-test' &&
event.event_type === 'transport_test';
const eventType = isTest
? 'transport_test'
: isAudit
? shouldNotify
? 'gcp_audit'
: 'audit_ignored'
: 'unknown';
results.push({
json: {
messageId: message.messageId,
publishTime: message.publishTime,
ackId,
event,
eventType,
shouldNotify,
service: service || null,
method: method || null,
user,
resource: audit.resourceName ?? null
}
});
} catch (error) {
results.push({
json: {
messageId:
message?.messageId ?? null,
ackId,
eventType: 'invalid',
shouldNotify: false,
error:
'No se pudo decodificar el mensaje'
}
});
}
}
}
return results;
Este código es una base para personalización. Antes de emplearlo en otro proyecto hay que verificar los nombres reales de los métodos, las exclusiones de cuentas de servicio y las políticas de riesgo de cada organización.
También conviene validar que los mensajes procedan de las fuentes esperadas y no confiar únicamente en que su JSON tiene estructura de auditoría.
7. Filtrar eventos: notificar lo importante sin saturar Slack
Después del nodo Code utilizamos un nodo IF.
La expresión principal es:
{{ $json.shouldNotify }}
Cuando el resultado es true, el evento continúa hacia el procesamiento de alertas.
Cuando es false, pasa a una segunda clasificación.
En la implementación distinguimos cinco categorías:
| Categoría | Acción |
|---|---|
gcp_audit crítico |
Evaluar y enviar alerta |
audit_ignored |
Confirmar sin notificar |
transport_test |
Confirmar sin notificar |
unknown |
Registrar en cuarentena |
invalid |
Registrar en cuarentena |
Esta clasificación es relevante porque no todas las entradas deben convertirse en alertas de seguridad.
Un monitoreo que publica demasiada información irrelevante acaba perdiendo eficacia operativa.
8. Evitar alertas duplicadas con n8n Data Tables
Uno de los problemas más importantes de los sistemas basados en mensajes es la posibilidad de entregas repetidas.
Para reducir las notificaciones duplicadas utilizamos una Data Table llamada:
seowmx_gcp_processed
Con las siguientes columnas:
| Columna | Tipo |
|---|---|
message_id |
String |
event_type |
String |
processed_at |
Date & Time |
status |
String |
Antes de publicar una alerta, n8n realiza una consulta:
Data Table → Get row(s)
Utilizando:
{{ $json.messageId }}
Como condición de igualdad sobre la columna message_id.
Si encuentra una fila, significa que el mensaje ya fue registrado como procesado. El flujo puede omitir Slack y proceder a confirmar la entrega.
Si no encuentra una fila, continúa hacia la publicación.
Un detalle importante de n8n
Cuando Get row(s) no encuentra resultados, puede producir un elemento vacío si se habilita Always Output Data.
Por ello utilizamos una condición que comprueba la existencia del identificador de fila:
{{ $json.id }}
Con el operador exists.
La rama verdadera corresponde a una coincidencia; la falsa corresponde a un mensaje nuevo.
En este diseño inicial, configurado para un mensaje por ejecución, el nodo que prepara Slack puede recuperar el evento original mediante una referencia a la salida del nodo de decodificación.
Esta referencia debe refactorizarse cuando se habiliten lotes de mensajes o múltiples ejecuciones concurrentes.
¿Es deduplicación exactamente una vez?
No.
Una Data Table consultada antes de insertar un registro no proporciona por sí sola una operación atómica de comprobación y reserva.
Dos ejecuciones concurrentes podrían consultar el mismo identificador antes de que alguna registre la alerta.
Además, si Slack acepta el mensaje pero falla la escritura en la tabla, un reintento podría volver a publicarlo.
Para sistemas de alta criticidad conviene implementar controles adicionales, como claves únicas, operaciones atómicas e idempotencia.
9. Construir el mensaje de alerta para Slack
El siguiente nodo Code transforma el evento de auditoría en una notificación legible.
Un mensaje útil debe identificar el usuario, servicio, operación, recurso, dirección IP y fecha.
Ejemplo de función para limpiar los valores que se publicarán:
const e =
$('Code in JavaScript').first().json;
const audit =
e.event?.protoPayload ?? {};
if (
e.eventType !== 'gcp_audit' ||
!e.ackId ||
!e.messageId
) {
throw new Error(
'Evento GCP incompleto o inválido'
);
}
const safe = value =>
String(value ?? 'N/D')
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/[\r\n`*~]/g, ' ')
.slice(0, 200);
const text = [
'🚨 *SEOwmx · Alerta Google Cloud*',
`*Usuario:* ${safe(e.user)}`,
`*Servicio:* ${safe(e.service)}`,
`*Operación:* ${safe(e.method)}`,
`*Recurso:* ${safe(e.resource)}`,
`*IP:* ${safe(audit.requestMetadata?.callerIp)}`,
`*Fecha UTC:* ${safe(e.event?.timestamp)}`,
`*Estado:* ${
audit.status?.code
? 'Error ' + audit.status.code
: 'Sin error reportado'
}`
].join('\n');
return {
json: {
...e,
slackText: text
}
};
El texto resultante se envía mediante un nodo HTTP Request al Incoming Webhook de Slack.
Método:POSTAutenticación:None, si se utiliza el Incoming Webhook correspondiente.
Body Content Type:JSONCuerpo:
{{ { "text": $json.slackText } }}
La URL del webhook debe almacenarse y protegerse como un secreto. Nunca debe publicarse en un repositorio, ejemplo de código real o documentación pública.
Para mayor seguridad pueden utilizarse mecanismos de credenciales compatibles con la instalación.
10. Registrar primero y confirmar después
Una decisión importante de la arquitectura es el orden de las operaciones:
Publicar en Slack
|
v
Registrar en Data Table
|
v
ACK de Pub/Sub
¿Por qué ese orden?
Porque queremos evitar confirmar un mensaje antes de haber registrado correctamente que fue atendido.
Después de una respuesta exitosa de Slack, insertamos una fila en seowmx_gcp_processed.
Por ejemplo:
message_id: 90000000000000001
event_type: gcp_audit
processed_at: fecha de ejecución
status: sent_to_slack
Finalmente enviamos el ACK mediante la API de Pub/Sub:
POST https://pubsub.googleapis.com/v1/projects/PROJECT_ID/subscriptions/SUBSCRIPTION_ID:acknowledge
Cuerpo:
{{ {
"ackIds": [
$('Code in JavaScript').first().json.ackId
]
} }}
Esta expresión corresponde al diseño inicial de un mensaje por ejecución. En un procesador por lotes cada confirmación debe asociarse a la entrega concreta del mensaje que se acaba de tratar.
Una respuesta HTTP exitosa indica que la solicitud se procesó sin error HTTP, pero siempre es conveniente verificar que el mensaje no reaparezca, especialmente cuando pudo vencer su plazo de confirmación.
11. Cuarentena: qué hacer con los mensajes inválidos
Durante el desarrollo identificamos otra situación relevante.
¿Qué pasa si Pub/Sub entrega un mensaje que no podemos interpretar?
Ignorarlo sin ACK puede provocar entregas repetidas. Confirmarlo inmediatamente, por otro lado, podría eliminar una evidencia útil para investigar el problema.
La solución utilizada fue una segunda Data Table:
seowmx_gcp_quarantine
Con los campos:
| Columna | Tipo |
|---|---|
message_id |
String |
event_type |
String |
error |
String |
received_at |
Date & Time |
Los mensajes unknown e invalid pasan por:
IF → Registrar cuarentena → ACK
Así, primero se conserva una referencia al evento y después se confirma la entrega.
Limitación importante: esta tabla inicial conserva metadatos y el motivo del error, no necesariamente el contenido bruto del mensaje. Si se necesita capacidad completa de reprocesamiento forense, conviene almacenar de forma segura el payload original o utilizar una dead-letter queue con políticas de retención y acceso adecuadas.
12. Manejo de fallos: reintentos y detención segura
Los nodos críticos fueron configurados con una política de reintentos.
En particular:
Retry On Fail: Enabled
Max Tries: 3
Wait Between Tries: 1000 ms
On Error: Stop Workflow
Esto se aplicó a los nodos de publicación, persistencia y confirmación.
La lógica es sencilla: si una operación crítica falla, no debemos continuar como si hubiera finalizado correctamente.
Por ejemplo, si Slack devuelve un error, no queremos que el sistema registre la alerta como enviada y confirme el mensaje sin más.
Sin embargo, los reintentos no solucionan todos los problemas.
Si Slack recibe una solicitud y la respuesta se pierde, un reintento puede publicar el mismo mensaje nuevamente. Lo mismo puede ocurrir cuando una inserción se completa, pero su confirmación no llega al cliente.
Estos escenarios requieren idempotencia y una estrategia de recuperación bien definida.
13. Crear un workflow independiente para errores
No basta con detectar incidentes en Google Cloud. También necesitamos saber si falla el sistema encargado de detectarlos.
Por eso se creó un segundo workflow en n8n:
Error Trigger
|
v
HTTP Request
|
v
Slack - Error de monitoreo
El nodo Error Trigger recibe información del workflow que ha fallado, siempre que el manejo de errores esté configurado correctamente y se trate de una ejecución compatible.
El mensaje puede construirse con la siguiente expresión:
{{ {
text:
"⚠️ *SEOwmx · ERROR DE MONITOREO GCP*\n" +
"*Workflow:* " +
($json.workflow?.name ?? "N/D") +
"\n" +
"*Nodo:* " +
($json.execution?.lastNodeExecuted ?? "N/D") +
"\n" +
"*Error:* " +
(
$json.execution?.error?.message ??
$json.trigger?.error?.message ??
"Error no especificado"
)
} }}
Después, desde los ajustes del workflow principal, se selecciona el workflow de errores correspondiente.
Esta separación mejora la observabilidad operativa.
No obstante, si el propio n8n está caído o Slack no está disponible, el workflow de errores puede no ejecutarse. Para operaciones críticas, conviene complementar este diseño con un monitor externo de disponibilidad y métricas de antigüedad de mensajes pendientes.
14. Problemas reales encontrados durante la implementación
Una parte valiosa de este proyecto fueron los problemas detectados durante las pruebas.
El nodo Data Table no se ejecutaba
Inicialmente apareció el mensaje:
Node was not executed. The execution took a different path.
El motivo no era un error en la tabla. El evento recibido estaba clasificado como transport_test y había seguido la rama destinada a los mensajes de prueba.
Lección: antes de modificar un nodo, hay que comprobar qué camino siguió realmente el mensaje en el historial de ejecución.
Los mensajes de prueba reaparecían
La suscripción devolvió en varias ocasiones un mensaje de prueba anterior.
Esto nos llevó a revisar los ackId, el ACK y el plazo de confirmación.
Lección: una solicitud de lectura y una confirmación son operaciones distintas. Consultar un mensaje no equivale a eliminarlo de la suscripción.
Los datos originales se perdían después de consultar la tabla
El nodo Get row(s) entregaba la fila encontrada o un elemento vacío, en lugar de conservar automáticamente toda la información de entrada.
En la primera versión, resolvimos este problema recuperando explícitamente los datos del nodo de decodificación.
Lección: en n8n hay que prestar atención al flujo de datos entre nodos, no solamente a sus conexiones visuales.
Era necesario separar los ACK
El diseño inicial podía llevar un mensaje duplicado a más de una ruta de confirmación.
Se corrigió separando los ACK de alertas nuevas, duplicados, mensajes conocidos sin notificación y cuarentena.
Lección: cada entrega debe seguir una ruta de tratamiento coherente y terminar en una confirmación correspondiente.
Había que observar también los fallos del monitoreo
Un sistema que únicamente envía alertas de seguridad puede fallar silenciosamente si no se vigilan sus propias ejecuciones.
La incorporación de Error Trigger y una notificación independiente proporciona una capa adicional de observabilidad.
15. ¿Qué resultados se verificaron?
Durante la implementación se comprobó el funcionamiento de varios componentes con eventos reales de Cloud Audit Logs.
Se verificó que Cloud Logging enviara registros administrativos hacia Pub/Sub, que n8n pudiera decodificarlos, que el flujo publicara una alerta en Slack y que el registro correspondiente se guardara en una Data Table.
También se configuraron las rutas de confirmación, clasificación y cuarentena.
Es importante distinguir entre una integración funcional validada y un sistema completamente endurecido.
La deduplicación concurrente, las condiciones de fallo prolongado, la recuperación de mensajes inválidos y la disponibilidad de la infraestructura requieren validaciones adicionales para un entorno de alta criticidad.
No presentamos métricas inventadas de reducción de incidentes ni afirmamos capacidades de detección que no fueron probadas.
16. Mejoras recomendadas para producción
La arquitectura puede evolucionar en varias direcciones.
Idempotencia robusta. Usar claves únicas y mecanismos de reserva atómica de eventos.
Procesamiento por lotes. Incrementar maxMessages y asegurar que cada elemento conserve su propio messageId y ackId.
Control de concurrencia. Evitar que ejecuciones simultáneas procesen el mismo evento sin coordinación.
Dead-letter queue. Conservar de forma recuperable los mensajes que fallen repetidamente.
Monitoreo del backlog. Observar la cantidad y la antigüedad de los mensajes pendientes en Pub/Sub.
Severidad por operación. Diferenciar cambios administrativos informativos, sospechosos y de alto riesgo.
Detección de contexto. Correlacionar usuarios, direcciones IP, horarios, recursos y comportamiento habitual.
Integridad de las notificaciones. Evitar construir mensajes de Slack con campos no validados o contenido potencialmente manipulable.
Supervisión externa. Detectar interrupciones de n8n o del propio canal de alertas.
Estas mejoras permiten avanzar desde una automatización de seguridad útil hacia un sistema más robusto y auditable.
Preguntas frecuentes
¿Se puede monitorear Google Cloud con n8n?
Sí. n8n puede consultar Pub/Sub mediante su API, decodificar registros de Cloud Audit Logs y automatizar acciones como publicar alertas, almacenar identificadores y ejecutar confirmaciones.
¿Es necesario instalar un agente en cada máquina virtual?
No para este diseño. El monitoreo descrito utiliza registros administrativos de Google Cloud y servicios gestionados. La detección de procesos dentro del sistema operativo, comandos SSH o cambios en archivos requiere mecanismos adicionales.
¿Para qué sirve Pub/Sub en esta arquitectura?
Pub/Sub desacopla la generación de registros de auditoría del procesamiento realizado por n8n. También permite gestionar entregas, confirmaciones y reintentos.
¿Qué diferencia existe entre messageId y ackId?
messageId identifica un mensaje publicado. ackId identifica una entrega recibida mediante una suscripción Pull y se utiliza para confirmar su procesamiento.
¿Qué pasa si Slack deja de responder?
El nodo puede reintentar la solicitud y detener el workflow si falla. Si el mensaje no se confirma, Pub/Sub puede volver a entregarlo. Esto ayuda a evitar pérdidas silenciosas, aunque también puede provocar notificaciones repetidas.
¿Se pueden evitar todas las alertas duplicadas?
No solamente con una consulta previa a una Data Table. Para garantías más fuertes se necesitan mecanismos de idempotencia y coordinación entre ejecuciones.
¿Cuánto cuesta construir un sistema de este tipo?
El costo depende del volumen de registros, el uso de Pub/Sub, el alojamiento de n8n, su base de datos, la retención y otros servicios utilizados. Debe estimarse con los precios vigentes y el volumen esperado de eventos. No existe un costo universal.
¿Puede sustituir a un SIEM empresarial?
Puede cubrir casos concretos de monitoreo y notificación, pero no reemplaza automáticamente las funciones completas de una plataforma SIEM empresarial.
Conclusión
Construir un sistema de alertas de seguridad en Google Cloud no exige necesariamente comenzar con una plataforma compleja.
Con Cloud Audit Logs, Log Router, Pub/Sub, n8n y Slack es posible diseñar un flujo que convierta operaciones administrativas en notificaciones contextualizadas y registre su procesamiento.
La parte más importante no es enviar un mensaje a Slack. Es diseñar correctamente las condiciones que determinan cuándo alertar, cuándo ignorar, cuándo registrar y cuándo confirmar.
Ese enfoque convierte una automatización sencilla en una base útil para desarrollar capacidades de monitoreo, observabilidad y respuesta a incidentes.
En SEOwmx continuaremos explorando arquitecturas reproducibles de ciberseguridad, infraestructura cloud y automatización, documentando tanto los resultados como las limitaciones técnicas.