Skip to main content

Audit Service

The Audit Service provides centralized, immutable audit logging for all authentication and authorization events in the Rippler platform. It stores structured audit logs with full query capabilities for compliance and security monitoring.

Architecture Diagram

The following diagram illustrates the internal architecture of the Audit Service, showing how different microservices log events, how they are processed and stored immutably in PostgreSQL, and how administrators can query audit logs.

Update the Architecture Diagram

To view and edit the architecture diagram:

  1. Open /docs/architecture/services/audit-service.drawio in diagrams.net or VS Code with the Draw.io extension
  2. The diagram shows the complete audit logging architecture including event collection from services, validation, immutable storage, and query capabilities
  3. After making changes, export to HTML and copy to /website/static/architecture/services/audit-service.drawio.html

Overview

Port: 18011
Technology: Spring Boot 3.2.0, Java 17, PostgreSQL
API Prefix: /api/v1/audit

Features

  • ✅ Centralized audit logging
  • ✅ Login event tracking
  • ✅ Permission granted/denied event tracking
  • ✅ Query by principal, event type, time range
  • ✅ Pagination support for large datasets
  • ✅ Indexed queries for performance
  • ✅ Immutable logs (no UPDATE/DELETE operations)

Architecture

graph LR
A[Services] -->|Log Events| B[Audit Service]
B -->|Store| C[PostgreSQL]
D[Admin] -->|Query| B
B -->|Return| D

Database Schema

audit_logs Table

CREATE TABLE audit_logs (
id BIGSERIAL PRIMARY KEY,
event_type VARCHAR(50) NOT NULL,
principal_subject VARCHAR(255),
resource VARCHAR(500),
action VARCHAR(100),
result VARCHAR(20) NOT NULL,
ip_address VARCHAR(45),
user_agent VARCHAR(500),
details TEXT,
timestamp TIMESTAMP NOT NULL
);

-- Indexes for performance
CREATE INDEX idx_audit_event_type ON audit_logs(event_type);
CREATE INDEX idx_audit_principal ON audit_logs(principal_subject);
CREATE INDEX idx_audit_timestamp ON audit_logs(timestamp);
CREATE INDEX idx_audit_result ON audit_logs(result);

Event Types

Event TypeDescriptionWhen to Use
LOGINUser login eventsAfter successful/failed login
PERMISSION_GRANTEDPermission check succeededWhen access is granted
PERMISSION_DENIEDPermission check failedWhen access is denied
LOGOUTUser logout eventsAfter user logout
TOKEN_REFRESHToken refresh eventsWhen JWT token is refreshed

Result Types

ResultDescription
SUCCESSOperation succeeded
FAILUREOperation failed
DENIEDAccess denied

API Endpoints

Log Events

Log Login Event

POST /api/v1/audit/login
Content-Type: application/json

{
"principalSubject": "user|alice",
"result": "SUCCESS",
"ipAddress": "192.168.1.100",
"userAgent": "Mozilla/5.0...",
"details": "User logged in successfully"
}

Response: 201 Created

{
"id": 12345,
"eventType": "LOGIN",
"principalSubject": "user|alice",
"result": "SUCCESS",
"ipAddress": "192.168.1.100",
"userAgent": "Mozilla/5.0...",
"details": "User logged in successfully",
"timestamp": "2024-01-15T10:30:00"
}

Log Permission Granted

POST /api/v1/audit/permissionGranted
Content-Type: application/json

{
"principalSubject": "user|alice",
"resource": "service:impact-analyzer",
"action": "impact:run",
"ipAddress": "192.168.1.100",
"details": "User has required permission"
}

Log Permission Denied

POST /api/v1/audit/permissionDenied
Content-Type: application/json

{
"principalSubject": "user|bob",
"resource": "service:impact-analyzer",
"action": "impact:admin",
"ipAddress": "192.168.1.101",
"details": "User does not have required permission"
}

Query Logs

Get All Logs (Paginated)

GET /api/v1/audit?page=0&size=20&sort=timestamp,desc

Response: 200 OK

{
"content": [
{
"id": 12345,
"eventType": "LOGIN",
"principalSubject": "user|alice",
"result": "SUCCESS",
"timestamp": "2024-01-15T10:30:00",
...
}
],
"pageable": {
"pageNumber": 0,
"pageSize": 20
},
"totalElements": 150,
"totalPages": 8
}

Get Logs by Principal

GET /api/v1/audit/principal/user|alice?page=0&size=20

Returns all audit logs for a specific user.

Get Logs by Event Type

GET /api/v1/audit/eventType/LOGIN?page=0&size=20

Filter logs by event type (LOGIN, PERMISSION_GRANTED, PERMISSION_DENIED, etc.).

Get Logs by Time Range

GET /api/v1/audit/timerange?start=2024-01-01T00:00:00&end=2024-01-31T23:59:59&page=0&size=50

Query logs within a specific time window.

Environment Variables

# Database
SPRING_DATASOURCE_URL=jdbc:postgresql://postgres:5432/rippler_audit
SPRING_DATASOURCE_USERNAME=rippler
SPRING_DATASOURCE_PASSWORD=rippler_pass

# Application
SERVER_PORT=8011
SPRING_JPA_HIBERNATE_DDL_AUTO=update

Integration with Services

Services should log audit events to the Audit Service for all authentication and authorization activities.

Example: Log Login Event

@Autowired
private RestTemplate restTemplate;

public void logLoginEvent(String userId, String result, String ipAddress, String userAgent) {
AuditLog log = AuditLog.builder()
.principalSubject(userId)
.result(result)
.ipAddress(ipAddress)
.userAgent(userAgent)
.details("Login attempt")
.build();

restTemplate.postForObject(
"http://audit-service:8011/api/v1/audit/login",
log,
AuditLog.class
);
}

Example: Log Permission Denial

public void logPermissionDenied(String userId, String resource, String action) {
AuditLog log = AuditLog.builder()
.principalSubject(userId)
.resource(resource)
.action(action)
.details("User attempted unauthorized action")
.build();

restTemplate.postForObject(
"http://audit-service:8011/api/v1/audit/permissionDenied",
log,
AuditLog.class
);
}

Query Examples

Find Failed Login Attempts

curl "http://localhost:18011/api/v1/audit/eventType/LOGIN?page=0&size=50" \
| jq '.content[] | select(.result == "FAILURE")'

Get User Activity

curl "http://localhost:18011/api/v1/audit/principal/user|alice?page=0&size=100"

Recent Permission Denials

curl "http://localhost:18011/api/v1/audit/eventType/PERMISSION_DENIED?page=0&size=20"

Activity in Date Range

curl "http://localhost:18011/api/v1/audit/timerange?start=2024-01-01T00:00:00&end=2024-01-31T23:59:59&page=0&size=100"

Health Check

GET /actuator/health

Response:

{
"status": "UP",
"components": {
"db": { "status": "UP" }
}
}

Development

Building

cd services/audit-service
mvn clean package

Running Locally

# With Docker Compose
docker-compose up audit-service

# Standalone
java -jar target/audit-service-1.0.0.jar

Testing

# Log a login event
curl -X POST http://localhost:18011/api/v1/audit/login \
-H "Content-Type: application/json" \
-d '{
"principalSubject": "user|test",
"result": "SUCCESS",
"ipAddress": "127.0.0.1"
}'

# Query logs
curl "http://localhost:18011/api/v1/audit?page=0&size=10"

Monitoring

Key metrics available at /actuator/metrics:

  • http.server.requests - API request latency
  • jvm.memory.used - Memory usage
  • jdbc.connections.active - Database connections
  • Custom metrics for log volume

Compliance & Retention

Audit Log Retention

By default, audit logs are stored indefinitely. Consider implementing retention policies based on compliance requirements:

  • GDPR: 6 months to 2 years
  • SOX: 7 years
  • HIPAA: 6 years
  • PCI DSS: 1 year

Implementation Options

  1. PostgreSQL Table Partitioning: Partition by month for easier archival
  2. Archival Process: Move old logs to cold storage
  3. Log Forwarding: Stream to external SIEM (Splunk, ELK, etc.)

Security Considerations

Immutability

The Audit Service does not expose UPDATE or DELETE operations. Once logged, events cannot be modified.

Access Control

  • Only administrators should query audit logs
  • Implement JWT validation for all endpoints (except health)
  • Consider separate read-only role for auditors

Data Protection

  • Mask sensitive data in logs (passwords, tokens, PII)
  • Encrypt database at rest in production
  • Use TLS for data in transit
  • Consider log forwarding to external SIEM for redundancy

Best Practices

What to Log

Do Log:

  • All login attempts (success and failure)
  • Permission checks (granted and denied)
  • Role assignments and changes
  • Token refresh events
  • Administrative actions

Don't Log:

  • Passwords or secrets
  • Complete JWT tokens
  • Credit card numbers
  • Other PII unless necessary

Log Details

Include contextual information:

  • User identifier (principal subject)
  • IP address
  • User agent
  • Resource accessed
  • Action attempted
  • Outcome (success/failure/denied)
  • Timestamp

Performance

  • Use pagination for large result sets
  • Leverage database indexes for common queries
  • Consider archiving old logs
  • Monitor disk usage

Troubleshooting

Database Connection Issues

  1. Check PostgreSQL: docker-compose ps postgres
  2. Verify database exists: docker-compose exec postgres psql -U rippler -l
  3. Check connection string

Slow Queries

  1. Check indexes are present: \d+ audit_logs in psql
  2. Add indexes for common query patterns
  3. Consider table partitioning for large datasets
  4. Review query execution plans

Disk Space Issues

  1. Monitor disk usage: df -h
  2. Implement retention policy
  3. Archive old logs to cold storage
  4. Consider log compression

Integration Points

Services That Should Log to Audit Service

  1. API Gateway - All login attempts, token validations
  2. Auth Service - Permission checks (granted/denied)
  3. All Services - Permission denials, unauthorized access attempts
  4. Keycloak - Login events (via webhook or custom event listener)

See Also