audit

package
v0.1.2-stable Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 27, 2026 License: MIT Imports: 9 Imported by: 0

README

Audit Package

Audit logging functionality for security-sensitive events in the LLM proxy, with immutable semantics for compliance.

Purpose & Responsibilities

  • Security Event Tracking: Records security-sensitive operations (token lifecycle, project management, proxy access)
  • Immutable Audit Trail: Write-once semantics for compliance requirements
  • Dual Backend Support: Writes to both file (JSONL) and database
  • Standardized Event Schema: Canonical fields for consistent audit analysis
  • Token Obfuscation: Automatically redacts sensitive token data

Relationship to Application Logging

Aspect Application Logging Audit Logging
Purpose Debugging, monitoring Security, compliance
Events All operations Security-sensitive only
Retention Rotated regularly Long-term retention
Modification Can be filtered/suppressed Immutable records
Package internal/logging internal/audit

Configuration Options

Environment Variable Description Default
AUDIT_LOG_FILE Path to audit log file ./data/audit.log
AUDIT_STORE_IN_DB Enable database audit storage true

Event Schema

Field Type Description
Timestamp time.Time When event occurred
Action string Operation type (e.g., token.create)
Actor string Who performed action
ProjectID string Affected project
RequestID string Request correlation
CorrelationID string Distributed tracing
ClientIP string Client IP address
Result ResultType success, failure, denied, error
Details map[string]any Additional context

Action Categories

Token Lifecycle Actions
Action Description
token.create New token created
token.read Token details accessed
token.update Token modified
token.revoke Single token revoked
token.revoke_batch Multiple tokens revoked
token.delete Token deleted
token.list Token listing accessed
token.validate Token validation attempted
token.access Token used for API access
Project Lifecycle Actions
Action Description
project.create New project created
project.read Project details accessed
project.update Project modified
project.delete Project deleted
project.list Project listing accessed
Other Actions
Action Description
proxy_request API request proxied (denied/error)
admin.login Admin UI login
admin.logout Admin UI logout
admin.access Admin resource accessed
audit.list Audit log listing
cache.purge Cache purge operation

Actor Types

Actor Description
system Automated system operations
anonymous Unauthenticated operations
admin Admin UI operations
management_api Management API operations
Token ID API operations (auto-obfuscated)

Architecture

flowchart TB
    subgraph Sources
        H[HTTP Handlers]
        M[Middleware]
        S[Services]
    end
    
    subgraph "Audit Logger"
        L[Logger]
        F[File Backend]
        D[Database Backend]
    end
    
    H -->|NewEvent| L
    M -->|NewEvent| L
    S -->|NewEvent| L
    
    L -->|JSONL| F
    L -->|SQL| D

Event Builder Methods

Events are created using a fluent builder pattern:

Method Description
NewEvent(action, actor, result) Create new event
WithProjectID(id) Set project ID
WithRequestID(id) Set request ID
WithCorrelationID(id) Set correlation ID
WithClientIP(ip) Set client IP
WithTokenID(token) Set token (auto-obfuscated)
WithError(err) Add error details
WithUserAgent(ua) Add user agent
WithHTTPMethod(method) Add HTTP method
WithEndpoint(path) Add endpoint path
WithDuration(d) Add operation duration
WithReason(reason) Add reason/description
WithDetail(key, value) Add custom detail

File Output Format

Audit events are written as JSON Lines (JSONL):

{"timestamp":"2024-01-15T10:30:45Z","action":"token.create","actor":"management_api","project_id":"proj-123","result":"success"}
{"timestamp":"2024-01-15T10:31:00Z","action":"proxy_request","actor":"sk-ab...89","result":"denied","details":{"reason":"project_inactive"}}

Integration Flow

sequenceDiagram
    participant Handler
    participant AuditLogger
    participant File
    participant Database
    
    Handler->>AuditLogger: NewEvent(action, actor, result)
    Handler->>AuditLogger: WithProjectID(id)
    Handler->>AuditLogger: Log(event)
    
    AuditLogger->>File: Write JSONL
    AuditLogger->>Database: INSERT (if enabled)

Security Considerations

  1. Token Obfuscation: Always use WithTokenID() to ensure tokens are obfuscated
  2. No Secrets in Details: Never add raw secrets to the Details map
  3. File Permissions: Audit log files are created with 0644 permissions; consider 0600 and dedicated user ownership for production
  4. Sync on Write: Each event triggers a file sync for durability

Testing Guidance

  • Unit Tests: Use audit.NewNullLogger() to discard events during tests
  • Event Content: Create events with NewEvent() and assert field values
  • File Output: Use t.TempDir() for testing file-based logging
  • Existing Tests: See logger_test.go, schema_test.go for examples

Files

File Description
logger.go Audit logger implementation with file and database backends
schema.go Event struct, action constants, result types, and builder methods

Documentation

Overview

Package audit provides audit logging functionality for security-sensitive events in the LLM proxy. It implements a separate audit sink with immutable semantics for compliance and security investigations.

Index

Constants

View Source
const (
	// Token lifecycle actions
	ActionTokenCreate      = "token.create"
	ActionTokenRead        = "token.read"
	ActionTokenUpdate      = "token.update"
	ActionTokenRevoke      = "token.revoke"
	ActionTokenRevokeBatch = "token.revoke_batch"
	ActionTokenDelete      = "token.delete"
	ActionTokenList        = "token.list"
	ActionTokenValidate    = "token.validate"
	ActionTokenAccess      = "token.access"

	// Project lifecycle actions
	ActionProjectCreate = "project.create"
	ActionProjectRead   = "project.read"
	ActionProjectUpdate = "project.update"
	ActionProjectDelete = "project.delete"
	ActionProjectList   = "project.list"

	// Proxy request actions
	ActionProxyRequest = "proxy_request"

	// Admin actions
	ActionAdminLogin  = "admin.login"
	ActionAdminLogout = "admin.logout"
	ActionAdminAccess = "admin.access"

	// Audit actions
	ActionAuditList = "audit.list"
	ActionAuditShow = "audit.show"

	// Cache actions
	ActionCachePurge = "cache.purge"
)

Action constants for standardized audit event types

View Source
const (
	ActorSystem     = "system"
	ActorAnonymous  = "anonymous"
	ActorAdmin      = "admin"
	ActorManagement = "management_api"
)

Actor types for common audit actors

Variables

This section is empty.

Functions

This section is empty.

Types

type DatabaseStore

type DatabaseStore interface {
	StoreAuditEvent(ctx context.Context, event *Event) error
}

DatabaseStore defines the interface for database audit storage

type Event

type Event struct {
	// Timestamp when the event occurred (ISO8601 format)
	Timestamp time.Time `json:"timestamp"`

	// Action describes what operation was performed (e.g., "token.create", "project.delete")
	Action string `json:"action"`

	// Actor identifies who performed the action (user ID, token ID, or system)
	Actor string `json:"actor"`

	// ProjectID identifies which project was affected (if applicable)
	ProjectID string `json:"project_id,omitempty"`

	// RequestID for correlation with request logs
	RequestID string `json:"request_id,omitempty"`

	// CorrelationID for tracing across services
	CorrelationID string `json:"correlation_id,omitempty"`

	// ClientIP is the IP address of the client making the request
	ClientIP string `json:"client_ip,omitempty"`

	// Result indicates success or failure of the operation
	Result ResultType `json:"result"`

	// Details contains additional context about the event (no secrets)
	Details map[string]interface{} `json:"details,omitempty"`
}

Event represents a security audit event with canonical fields. All audit events must include these core fields for compliance and investigation purposes.

func NewEvent

func NewEvent(action string, actor string, result ResultType) *Event

NewEvent creates a new audit event with the specified action and result. The timestamp is automatically set to the current time.

func (*Event) WithClientIP

func (e *Event) WithClientIP(clientIP string) *Event

WithClientIP sets the client IP address for the audit event

func (*Event) WithCorrelationID

func (e *Event) WithCorrelationID(correlationID string) *Event

WithCorrelationID sets the correlation ID for tracing across services

func (*Event) WithDetail

func (e *Event) WithDetail(key string, value interface{}) *Event

WithDetail adds a detail key-value pair to the audit event. Secrets and sensitive information should be obfuscated before calling this method.

func (*Event) WithDuration

func (e *Event) WithDuration(duration time.Duration) *Event

WithDuration adds the operation duration to the audit event details

func (*Event) WithEndpoint

func (e *Event) WithEndpoint(endpoint string) *Event

WithEndpoint adds the API endpoint to the audit event details

func (*Event) WithError

func (e *Event) WithError(err error) *Event

WithError adds error information to the audit event details

func (*Event) WithHTTPMethod

func (e *Event) WithHTTPMethod(method string) *Event

WithHTTPMethod adds the HTTP method to the audit event details

func (*Event) WithIPAddress

func (e *Event) WithIPAddress(ip string) *Event

WithIPAddress adds the client IP address to the audit event details Deprecated: Use WithClientIP instead for first-class IP field support

func (*Event) WithProjectID

func (e *Event) WithProjectID(projectID string) *Event

WithProjectID sets the project ID for the audit event

func (*Event) WithReason

func (e *Event) WithReason(reason string) *Event

WithReason adds a reason/description to the audit event details

func (*Event) WithRequestID

func (e *Event) WithRequestID(requestID string) *Event

WithRequestID sets the request ID for correlation with request logs

func (*Event) WithTokenID

func (e *Event) WithTokenID(token string) *Event

WithTokenID adds an obfuscated token ID to the audit event details

func (*Event) WithUserAgent

func (e *Event) WithUserAgent(userAgent string) *Event

WithUserAgent adds the user agent to the audit event details

type Logger

type Logger struct {
	// contains filtered or unexported fields
}

Logger handles writing audit events to multiple backends (file and database) with immutable semantics. It provides thread-safe operations and ensures all audit events are persisted.

func NewLogger

func NewLogger(config LoggerConfig) (*Logger, error)

NewLogger creates a new audit logger that writes to the specified file. If createDir is true, it will create parent directories if they don't exist. If a database store is provided, events will also be persisted to the database.

func NewNullLogger

func NewNullLogger() *Logger

NewNullLogger creates a logger that discards all events. Useful for testing or when audit logging is disabled.

func (*Logger) Close

func (l *Logger) Close() error

Close closes the audit log file. After calling Close, the logger should not be used for logging.

func (*Logger) GetPath

func (l *Logger) GetPath() string

GetPath returns the file path of the audit log

func (*Logger) Log

func (l *Logger) Log(event *Event) error

Log writes an audit event to both file and database backends. Events are written as JSON lines (JSONL format) for easy parsing. This method is thread-safe.

type LoggerConfig

type LoggerConfig struct {
	// FilePath is the path to the audit log file
	FilePath string
	// CreateDir determines whether to create parent directories if they don't exist
	CreateDir bool
	// DatabaseStore is an optional database backend for audit events
	DatabaseStore DatabaseStore
	// EnableDatabase determines whether to store events in database
	EnableDatabase bool
}

LoggerConfig holds configuration for the audit logger

type ResultType

type ResultType string

ResultType represents the outcome of an audited operation

const (
	// ResultSuccess indicates the operation completed successfully
	ResultSuccess ResultType = "success"

	// ResultFailure indicates the operation failed
	ResultFailure ResultType = "failure"

	// ResultDenied indicates the operation was denied (e.g., due to policy)
	ResultDenied ResultType = "denied"

	// ResultError indicates the operation encountered an error
	ResultError ResultType = "error"
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL