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.
To view and edit the architecture diagram:
- Open
/docs/architecture/services/audit-service.drawioin diagrams.net or VS Code with the Draw.io extension - The diagram shows the complete audit logging architecture including event collection from services, validation, immutable storage, and query capabilities
- 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 Type | Description | When to Use |
|---|---|---|
| LOGIN | User login events | After successful/failed login |
| PERMISSION_GRANTED | Permission check succeeded | When access is granted |
| PERMISSION_DENIED | Permission check failed | When access is denied |
| LOGOUT | User logout events | After user logout |
| TOKEN_REFRESH | Token refresh events | When JWT token is refreshed |
Result Types
| Result | Description |
|---|---|
| SUCCESS | Operation succeeded |
| FAILURE | Operation failed |
| DENIED | Access 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 latencyjvm.memory.used- Memory usagejdbc.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
- PostgreSQL Table Partitioning: Partition by month for easier archival
- Archival Process: Move old logs to cold storage
- 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
- Check PostgreSQL:
docker-compose ps postgres - Verify database exists:
docker-compose exec postgres psql -U rippler -l - Check connection string
Slow Queries
- Check indexes are present:
\d+ audit_logsin psql - Add indexes for common query patterns
- Consider table partitioning for large datasets
- Review query execution plans
Disk Space Issues
- Monitor disk usage:
df -h - Implement retention policy
- Archive old logs to cold storage
- Consider log compression
Integration Points
Services That Should Log to Audit Service
- API Gateway - All login attempts, token validations
- Auth Service - Permission checks (granted/denied)
- All Services - Permission denials, unauthorized access attempts
- Keycloak - Login events (via webhook or custom event listener)
See Also
- Auth Service - RBAC and permission management
- SSO Setup Guide - Complete SSO + RBAC setup
- API Gateway - JWT validation and routing