UNPKG

kafka-pub-sub

Version:

Enterprise-grade Kafka publish/subscribe library for Node.js — producer pool, batch sending, DLQ, SSL/SASL, multi-broker, and real-world industry examples.

185 lines (158 loc) 6.74 kB
/** * Compliance & Audit Logging — Consumer * * A compliance audit consumer that: * - Persists every event to a write-once data store (simulated) * - Detects security anomalies in real time * - Tracks GDPR data-subject access requests (DSAR) * - Never uses DLQ (audit events must not be silently discarded) * * In production this would write to: * - AWS S3 / GCS (long-term immutable storage) * - Elasticsearch (searchable audit index) * - PostgreSQL with append-only table (WORM-equivalent) * * Run: * node examples/audit/auditConsumer.js */ require('dotenv').config({ path: require('path').resolve(__dirname, '../../.env') }); const { ConsumeEvent } = require('../../index'); // eslint-disable-next-line no-console const log = (service, ...args) => console.log(`[${new Date().toISOString()}] [${service}]`, ...args); // Simulated in-memory audit store (use S3/Postgres/Elasticsearch in production) const auditStore = []; const DSAR_REQUESTS = new Set(['CUST-7890']); // data subjects with active access requests const persistToStore = async (event) => { auditStore.push({ ...event, _persistedAt: new Date().toISOString() }); // In production: INSERT INTO audit_log ... (append-only, no DELETE/UPDATE) }; // ── User action consumer ────────────────────────────────────────────────────── async function startUserActionConsumer() { return ConsumeEvent( 'audit.user-action', async (msg) => { const { actor, action, resource, outcome, occurredAt } = msg.value.data || msg.value; await persistToStore({ topic: 'audit.user-action', actor, action, resource, outcome, occurredAt }); log('USER-AUDIT', `${actor.id}${action} on ${resource.type}:${resource.id}${outcome}`); }, { groupId: 'audit-consumer-user-actions', fromBeginning: true, retry: 10, // audit consumers get many retries dlq: false, // audit events must NEVER be dropped — surface error instead } ); } // ── Data access consumer (GDPR) ─────────────────────────────────────────────── async function startDataAccessConsumer() { return ConsumeEvent( 'audit.data-access', async (msg) => { const payload = msg.value.data || msg.value; const { actor, action, resource, outcome, occurredAt, metadata } = payload; await persistToStore({ topic: 'audit.data-access', ...payload }); log( 'DATA-AUDIT', `${actor.id} (${actor.type}) ${action} ${resource.type}:${resource.id || 'query'}${outcome} | basis=${metadata?.legalBasis || 'n/a'}` ); // GDPR DSAR detection: if the accessed resource matches a data subject // with an active access request, flag it for DSAR report generation const subjectId = resource.id || resource.targetCustomerId; if (DSAR_REQUESTS.has(subjectId)) { log( 'DSAR-TRACKER', `⚑ Access to DSAR subject ${subjectId} recorded — event will be included in subject access report` ); // In production: tag record in DSAR processing queue } }, { groupId: 'audit-consumer-data-access', fromBeginning: true, retry: 10, dlq: false, } ); } // ── Security event consumer ─────────────────────────────────────────────────── async function startSecurityConsumer() { return ConsumeEvent( 'audit.security', async (msg) => { const payload = msg.value.data || msg.value; const { actor, action, resource, outcome, metadata } = payload; await persistToStore({ topic: 'audit.security', ...payload }); if (outcome === 'failure') { log( 'SECURITY-ALERT', `⚠ SECURITY EVENT: ${actor.id} attempted ${action} on ${resource.type}${outcome}` ); if (metadata?.alertSent) { log('SECURITY-ALERT', ' → On-call team already notified'); } // In production: push to PagerDuty / Splunk SIEM / Chronicle } else { log('SECURITY-AUDIT', `${actor.id}${action}${outcome}`); } }, { groupId: 'audit-consumer-security', fromBeginning: true, retry: 10, dlq: false, } ); } // ── System event consumer (SOC 2) ──────────────────────────────────────────── async function startSystemEventConsumer() { return ConsumeEvent( 'audit.system-event', async (msg) => { const payload = msg.value.data || msg.value; const { actor, action, resource, outcome, metadata } = payload; await persistToStore({ topic: 'audit.system-event', ...payload }); log( 'SYSTEM-AUDIT', `${actor.id}${action} ${resource.type}:${resource.id}${outcome} | pipeline=${metadata?.deployPipelineId || 'n/a'}` ); }, { groupId: 'audit-consumer-system', fromBeginning: true, retry: 10, dlq: false, } ); } // ── Stats reporter ──────────────────────────────────────────────────────────── function startStatsReporter() { return setInterval(() => { log('STATS', `Audit records persisted this session: ${auditStore.length}`); }, 15000); } // ── Main ────────────────────────────────────────────────────────────────────── async function main() { log('SYSTEM', 'Starting compliance audit consumers...'); const [stopUser, stopData, stopSecurity, stopSystem] = await Promise.all([ startUserActionConsumer(), startDataAccessConsumer(), startSecurityConsumer(), startSystemEventConsumer(), ]); const statsTimer = startStatsReporter(); log('SYSTEM', '✓ All audit consumers running (Ctrl+C to stop)'); const shutdown = async () => { clearInterval(statsTimer); log('STATS', `Total audit records persisted: ${auditStore.length}`); await Promise.all([stopUser(), stopData(), stopSecurity(), stopSystem()]); process.exit(0); }; process.on('SIGTERM', shutdown); process.on('SIGINT', shutdown); } main().catch((err) => { // eslint-disable-next-line no-console console.error('Audit consumer startup failed:', err); process.exit(1); });