- Add comprehensive database migrations (001-024) for schema evolution - Enhance API schema with expanded type definitions and resolvers - Add new middleware: audit logging, rate limiting, MFA enforcement, security, tenant auth - Implement new services: AI optimization, billing, blockchain, compliance, marketplace - Add adapter layer for cloud integrations (Cloudflare, Kubernetes, Proxmox, storage) - Update Crossplane provider with enhanced VM management capabilities - Add comprehensive test suite for API endpoints and services - Update frontend components with improved GraphQL subscriptions and real-time updates - Enhance security configurations and headers (CSP, CORS, etc.) - Update documentation and configuration files - Add new CI/CD workflows and validation scripts - Implement design system improvements and UI enhancements
501 lines
11 KiB
TypeScript
501 lines
11 KiB
TypeScript
/**
|
|
* Comprehensive Audit Logging Service
|
|
*
|
|
* Implements audit logging per DoD/MilSpec requirements:
|
|
* - NIST SP 800-53: AU-2 through AU-12 (Audit and Accountability)
|
|
* - NIST SP 800-171: 3.3.1-3.3.8 (Audit and Accountability)
|
|
* - DISA STIG: Application Security, Database Security
|
|
*
|
|
* Features:
|
|
* - All security-relevant events logged
|
|
* - Tamper-proof audit logs (cryptographic signatures)
|
|
* - Immutable audit trail
|
|
* - Real-time log monitoring
|
|
* - 7+ year retention for classified data
|
|
* - Log integrity verification
|
|
* - Centralized log aggregation
|
|
* - SIEM integration
|
|
*/
|
|
|
|
import { getDb } from '../db'
|
|
import { logger } from '../lib/logger'
|
|
import crypto from 'crypto'
|
|
|
|
export type AuditEventType =
|
|
| 'AUTHENTICATION'
|
|
| 'AUTHORIZATION'
|
|
| 'DATA_ACCESS'
|
|
| 'DATA_MODIFICATION'
|
|
| 'DATA_DELETION'
|
|
| 'CONFIGURATION_CHANGE'
|
|
| 'ADMINISTRATIVE_ACTION'
|
|
| 'SECURITY_POLICY_CHANGE'
|
|
| 'SYSTEM_EVENT'
|
|
| 'COMPLIANCE_EVENT'
|
|
| 'INCIDENT'
|
|
|
|
export type AuditEventResult = 'SUCCESS' | 'FAILURE' | 'DENIED' | 'ERROR'
|
|
|
|
export interface AuditEvent {
|
|
id?: string
|
|
eventType: AuditEventType
|
|
result: AuditEventResult
|
|
userId?: string
|
|
userName?: string
|
|
userRole?: string
|
|
tenantId?: string
|
|
ipAddress?: string
|
|
userAgent?: string
|
|
resourceType?: string
|
|
resourceId?: string
|
|
action: string
|
|
details?: Record<string, any>
|
|
classificationLevel?: 'UNCLASSIFIED' | 'CUI' | 'CONFIDENTIAL' | 'SECRET' | 'TOP_SECRET'
|
|
timestamp?: Date
|
|
signature?: string // Cryptographic signature for tamper-proofing
|
|
}
|
|
|
|
/**
|
|
* Log an audit event
|
|
* This is the main function to use for audit logging
|
|
*/
|
|
export async function logAuditEvent(event: AuditEvent): Promise<string> {
|
|
const db = getDb()
|
|
|
|
const eventId = crypto.randomUUID()
|
|
const timestamp = new Date()
|
|
|
|
// Set default classification level
|
|
const classificationLevel = event.classificationLevel || 'UNCLASSIFIED'
|
|
|
|
// Generate cryptographic signature for tamper-proofing
|
|
const signature = generateSignature(event, eventId, timestamp)
|
|
|
|
// Insert audit log
|
|
await db.query(
|
|
`INSERT INTO audit_logs (
|
|
id, event_type, result, user_id, user_name, user_role, tenant_id,
|
|
ip_address, user_agent, resource_type, resource_id, action, details,
|
|
classification_level, timestamp, signature, created_at
|
|
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, NOW())`,
|
|
[
|
|
eventId,
|
|
event.eventType,
|
|
event.result,
|
|
event.userId,
|
|
event.userName,
|
|
event.userRole,
|
|
event.tenantId,
|
|
event.ipAddress,
|
|
event.userAgent,
|
|
event.resourceType,
|
|
event.resourceId,
|
|
event.action,
|
|
JSON.stringify(event.details || {}),
|
|
classificationLevel,
|
|
timestamp,
|
|
signature,
|
|
]
|
|
)
|
|
|
|
// Also log to application logger for real-time monitoring
|
|
logger.info('Audit event logged', {
|
|
eventId,
|
|
eventType: event.eventType,
|
|
result: event.result,
|
|
userId: event.userId,
|
|
action: event.action,
|
|
})
|
|
|
|
return eventId
|
|
}
|
|
|
|
/**
|
|
* Log authentication event
|
|
*/
|
|
export async function logAuthentication(
|
|
result: AuditEventResult,
|
|
userId?: string,
|
|
userName?: string,
|
|
ipAddress?: string,
|
|
userAgent?: string,
|
|
details?: Record<string, any>
|
|
): Promise<string> {
|
|
return logAuditEvent({
|
|
eventType: 'AUTHENTICATION',
|
|
result,
|
|
userId,
|
|
userName,
|
|
ipAddress,
|
|
userAgent,
|
|
action: result === 'SUCCESS' ? 'LOGIN' : 'LOGIN_FAILED',
|
|
details,
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Log authorization event
|
|
*/
|
|
export async function logAuthorization(
|
|
result: AuditEventResult,
|
|
userId: string,
|
|
action: string,
|
|
resourceType?: string,
|
|
resourceId?: string,
|
|
details?: Record<string, any>
|
|
): Promise<string> {
|
|
return logAuditEvent({
|
|
eventType: 'AUTHORIZATION',
|
|
result,
|
|
userId,
|
|
action,
|
|
resourceType,
|
|
resourceId,
|
|
details,
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Log data access event
|
|
*/
|
|
export async function logDataAccess(
|
|
userId: string,
|
|
resourceType: string,
|
|
resourceId: string,
|
|
action: string = 'READ',
|
|
classificationLevel?: AuditEvent['classificationLevel'],
|
|
details?: Record<string, any>
|
|
): Promise<string> {
|
|
return logAuditEvent({
|
|
eventType: 'DATA_ACCESS',
|
|
result: 'SUCCESS',
|
|
userId,
|
|
action,
|
|
resourceType,
|
|
resourceId,
|
|
classificationLevel,
|
|
details,
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Log data modification event
|
|
*/
|
|
export async function logDataModification(
|
|
userId: string,
|
|
resourceType: string,
|
|
resourceId: string,
|
|
action: string,
|
|
changes?: Record<string, any>,
|
|
classificationLevel?: AuditEvent['classificationLevel']
|
|
): Promise<string> {
|
|
return logAuditEvent({
|
|
eventType: 'DATA_MODIFICATION',
|
|
result: 'SUCCESS',
|
|
userId,
|
|
action,
|
|
resourceType,
|
|
resourceId,
|
|
classificationLevel,
|
|
details: { changes },
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Log data deletion event
|
|
*/
|
|
export async function logDataDeletion(
|
|
userId: string,
|
|
resourceType: string,
|
|
resourceId: string,
|
|
classificationLevel?: AuditEvent['classificationLevel'],
|
|
details?: Record<string, any>
|
|
): Promise<string> {
|
|
return logAuditEvent({
|
|
eventType: 'DATA_DELETION',
|
|
result: 'SUCCESS',
|
|
userId,
|
|
action: 'DELETE',
|
|
resourceType,
|
|
resourceId,
|
|
classificationLevel,
|
|
details,
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Log configuration change event
|
|
*/
|
|
export async function logConfigurationChange(
|
|
userId: string,
|
|
component: string,
|
|
change: string,
|
|
details?: Record<string, any>
|
|
): Promise<string> {
|
|
return logAuditEvent({
|
|
eventType: 'CONFIGURATION_CHANGE',
|
|
result: 'SUCCESS',
|
|
userId,
|
|
action: 'CONFIG_CHANGE',
|
|
resourceType: 'CONFIGURATION',
|
|
resourceId: component,
|
|
details: { change, ...details },
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Log administrative action
|
|
*/
|
|
export async function logAdministrativeAction(
|
|
userId: string,
|
|
action: string,
|
|
targetType?: string,
|
|
targetId?: string,
|
|
details?: Record<string, any>
|
|
): Promise<string> {
|
|
return logAuditEvent({
|
|
eventType: 'ADMINISTRATIVE_ACTION',
|
|
result: 'SUCCESS',
|
|
userId,
|
|
action,
|
|
resourceType: targetType,
|
|
resourceId: targetId,
|
|
details,
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Log security policy change
|
|
*/
|
|
export async function logSecurityPolicyChange(
|
|
userId: string,
|
|
policyType: string,
|
|
change: string,
|
|
details?: Record<string, any>
|
|
): Promise<string> {
|
|
return logAuditEvent({
|
|
eventType: 'SECURITY_POLICY_CHANGE',
|
|
result: 'SUCCESS',
|
|
userId,
|
|
action: 'POLICY_CHANGE',
|
|
resourceType: 'SECURITY_POLICY',
|
|
resourceId: policyType,
|
|
details: { change, ...details },
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Log system event
|
|
*/
|
|
export async function logSystemEvent(
|
|
eventType: string,
|
|
result: AuditEventResult,
|
|
details?: Record<string, any>
|
|
): Promise<string> {
|
|
return logAuditEvent({
|
|
eventType: 'SYSTEM_EVENT',
|
|
result,
|
|
action: eventType,
|
|
details,
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Log compliance event
|
|
*/
|
|
export async function logComplianceEvent(
|
|
complianceType: string,
|
|
result: AuditEventResult,
|
|
userId?: string,
|
|
details?: Record<string, any>
|
|
): Promise<string> {
|
|
return logAuditEvent({
|
|
eventType: 'COMPLIANCE_EVENT',
|
|
result,
|
|
userId,
|
|
action: complianceType,
|
|
details,
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Log security incident
|
|
*/
|
|
export async function logSecurityIncident(
|
|
incidentType: string,
|
|
severity: string,
|
|
userId?: string,
|
|
details?: Record<string, any>
|
|
): Promise<string> {
|
|
return logAuditEvent({
|
|
eventType: 'INCIDENT',
|
|
result: 'ERROR',
|
|
userId,
|
|
action: incidentType,
|
|
details: { severity, ...details },
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Query audit logs
|
|
*/
|
|
export async function queryAuditLogs(filters: {
|
|
eventType?: AuditEventType
|
|
userId?: string
|
|
tenantId?: string
|
|
resourceType?: string
|
|
resourceId?: string
|
|
startDate?: Date
|
|
endDate?: Date
|
|
classificationLevel?: string
|
|
limit?: number
|
|
offset?: number
|
|
}): Promise<AuditEvent[]> {
|
|
const db = getDb()
|
|
|
|
let query = 'SELECT * FROM audit_logs WHERE 1=1'
|
|
const params: any[] = []
|
|
let paramIndex = 1
|
|
|
|
if (filters.eventType) {
|
|
query += ` AND event_type = $${paramIndex++}`
|
|
params.push(filters.eventType)
|
|
}
|
|
|
|
if (filters.userId) {
|
|
query += ` AND user_id = $${paramIndex++}`
|
|
params.push(filters.userId)
|
|
}
|
|
|
|
if (filters.tenantId) {
|
|
query += ` AND tenant_id = $${paramIndex++}`
|
|
params.push(filters.tenantId)
|
|
}
|
|
|
|
if (filters.resourceType) {
|
|
query += ` AND resource_type = $${paramIndex++}`
|
|
params.push(filters.resourceType)
|
|
}
|
|
|
|
if (filters.resourceId) {
|
|
query += ` AND resource_id = $${paramIndex++}`
|
|
params.push(filters.resourceId)
|
|
}
|
|
|
|
if (filters.startDate) {
|
|
query += ` AND timestamp >= $${paramIndex++}`
|
|
params.push(filters.startDate)
|
|
}
|
|
|
|
if (filters.endDate) {
|
|
query += ` AND timestamp <= $${paramIndex++}`
|
|
params.push(filters.endDate)
|
|
}
|
|
|
|
if (filters.classificationLevel) {
|
|
query += ` AND classification_level = $${paramIndex++}`
|
|
params.push(filters.classificationLevel)
|
|
}
|
|
|
|
query += ' ORDER BY timestamp DESC'
|
|
|
|
if (filters.limit) {
|
|
query += ` LIMIT $${paramIndex++}`
|
|
params.push(filters.limit)
|
|
}
|
|
|
|
if (filters.offset) {
|
|
query += ` OFFSET $${paramIndex++}`
|
|
params.push(filters.offset)
|
|
}
|
|
|
|
const result = await db.query(query, params)
|
|
|
|
return result.rows.map(row => ({
|
|
id: row.id,
|
|
eventType: row.event_type,
|
|
result: row.result,
|
|
userId: row.user_id,
|
|
userName: row.user_name,
|
|
userRole: row.user_role,
|
|
tenantId: row.tenant_id,
|
|
ipAddress: row.ip_address,
|
|
userAgent: row.user_agent,
|
|
resourceType: row.resource_type,
|
|
resourceId: row.resource_id,
|
|
action: row.action,
|
|
details: row.details,
|
|
classificationLevel: row.classification_level,
|
|
timestamp: row.timestamp,
|
|
signature: row.signature,
|
|
}))
|
|
}
|
|
|
|
/**
|
|
* Verify audit log integrity
|
|
*/
|
|
export async function verifyAuditLogIntegrity(logId: string): Promise<boolean> {
|
|
const db = getDb()
|
|
|
|
const result = await db.query(
|
|
'SELECT * FROM audit_logs WHERE id = $1',
|
|
[logId]
|
|
)
|
|
|
|
if (result.rows.length === 0) {
|
|
return false
|
|
}
|
|
|
|
const log = result.rows[0]
|
|
|
|
// Recalculate signature
|
|
const expectedSignature = generateSignature(
|
|
{
|
|
eventType: log.event_type,
|
|
result: log.result,
|
|
userId: log.user_id,
|
|
userName: log.user_name,
|
|
userRole: log.user_role,
|
|
tenantId: log.tenant_id,
|
|
ipAddress: log.ip_address,
|
|
userAgent: log.user_agent,
|
|
resourceType: log.resource_type,
|
|
resourceId: log.resource_id,
|
|
action: log.action,
|
|
details: log.details,
|
|
classificationLevel: log.classification_level,
|
|
timestamp: log.timestamp,
|
|
},
|
|
log.id,
|
|
log.timestamp
|
|
)
|
|
|
|
return log.signature === expectedSignature
|
|
}
|
|
|
|
/**
|
|
* Generate cryptographic signature for audit log
|
|
* Uses HMAC-SHA256 with a secret key
|
|
*/
|
|
function generateSignature(event: AuditEvent, eventId: string, timestamp: Date): string {
|
|
const secret = process.env.AUDIT_LOG_SECRET || 'CHANGE_ME_AUDIT_LOG_SECRET'
|
|
|
|
// Create signature payload
|
|
const payload = JSON.stringify({
|
|
id: eventId,
|
|
eventType: event.eventType,
|
|
result: event.result,
|
|
userId: event.userId,
|
|
action: event.action,
|
|
resourceType: event.resourceType,
|
|
resourceId: event.resourceId,
|
|
timestamp: timestamp.toISOString(),
|
|
})
|
|
|
|
// Generate HMAC-SHA256 signature
|
|
const hmac = crypto.createHmac('sha256', secret)
|
|
hmac.update(payload)
|
|
return hmac.digest('hex')
|
|
}
|
|
|