-- Migration 0047: Enhanced Audit Logging for Authentication Events -- AEG-AUTH-001: Comprehensive audit trail for security compliance -- Created: 2026-08-18 -- Status: READY FOR DEPLOYMENT BEGIN; -- 1. CREATE ENHANCED AUDIT LOG TABLE CREATE TABLE IF NOT EXISTS public.auth_audit_log ( audit_id UUID PRIMARY KEY DEFAULT gen_random_uuid(), -- Event Classification event_type VARCHAR(50) NOT NULL CHECK (event_type IN ('LOGIN', 'LOGOUT', 'MFA_SETUP', 'MFA_VERIFY', 'TOKEN_REFRESH', 'PERMISSION_DENIED', 'INVALID_TOKEN')), -- User Information identity_id UUID REFERENCES public.identity(identity_id) ON DELETE SET NULL, username VARCHAR(255), role VARCHAR(100), -- Request Context (for forensics) ip_address INET, user_agent TEXT, endpoint VARCHAR(255), http_method VARCHAR(10), -- Result Status status VARCHAR(20) NOT NULL CHECK (status IN ('SUCCESS', 'FAILURE', 'BLOCKED')), -- Error Details error_code VARCHAR(50), error_message TEXT, -- Security Details token_claims JSONB, -- For token analysis authentication_method VARCHAR(50), -- JWT, Header, MFA, etc. -- Lifecycle (immutable append-only) occurred_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, correlation_id UUID NOT NULL DEFAULT gen_random_uuid(), -- Indexing INDEX_created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP ); -- 2. INDEXES FOR PERFORMANCE & FORENSICS CREATE INDEX idx_auth_audit_identity ON public.auth_audit_log(identity_id); CREATE INDEX idx_auth_audit_occurred_at ON public.auth_audit_log(occurred_at DESC); CREATE INDEX idx_auth_audit_event_type ON public.auth_audit_log(event_type); CREATE INDEX idx_auth_audit_correlation ON public.auth_audit_log(correlation_id); CREATE INDEX idx_auth_audit_ip_address ON public.auth_audit_log(ip_address); CREATE INDEX idx_auth_audit_status ON public.auth_audit_log(status); CREATE INDEX idx_auth_audit_username ON public.auth_audit_log(username); -- 3. MONTHLY PARTITIONING (for large deployments) -- CREATE TABLE auth_audit_log_2026_08 PARTITION OF public.auth_audit_log -- FOR VALUES FROM ('2026-08-01') TO ('2026-09-01'); -- 4. IMMUTABILITY TRIGGER CREATE OR REPLACE FUNCTION prevent_audit_log_modification() RETURNS TRIGGER AS $$ BEGIN IF TG_OP = 'UPDATE' OR TG_OP = 'DELETE' THEN RAISE EXCEPTION 'Audit logs are immutable. Operation % not allowed.', TG_OP; END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER auth_audit_log_immutable BEFORE UPDATE OR DELETE ON public.auth_audit_log FOR EACH ROW EXECUTE FUNCTION prevent_audit_log_modification(); -- 5. VIEW FOR COMPLIANCE REPORTING CREATE OR REPLACE VIEW public.v_auth_audit_summary AS SELECT DATE_TRUNC('hour', occurred_at) AS hour, event_type, status, COUNT(*) AS count, COUNT(DISTINCT identity_id) AS unique_users, COUNT(DISTINCT ip_address) AS unique_ips FROM public.auth_audit_log WHERE occurred_at > NOW() - INTERVAL '30 days' GROUP BY DATE_TRUNC('hour', occurred_at), event_type, status ORDER BY hour DESC, event_type; -- 6. VIEW FOR FAILURE ANALYSIS CREATE OR REPLACE VIEW public.v_auth_failures AS SELECT identity_id, username, ip_address, event_type, error_code, error_message, occurred_at, COUNT(*) OVER ( PARTITION BY ip_address, DATE_TRUNC('minute', occurred_at) ORDER BY occurred_at ) AS attempts_per_minute FROM public.auth_audit_log WHERE status IN ('FAILURE', 'BLOCKED') AND occurred_at > NOW() - INTERVAL '24 hours' ORDER BY occurred_at DESC; COMMIT;