142 lines
4.0 KiB
Go
142 lines
4.0 KiB
Go
|
|
// audit.go provides comprehensive audit trail logging functionality for compliance and monitoring.
|
|||
|
|
// This file now uses the `log/slog` structured logging package introduced in Go 1.21.
|
|||
|
|
// A single environment variable LOG_FORMAT controls the output format:
|
|||
|
|
//
|
|||
|
|
// LOG_FORMAT=text -> human‑readable text (default)
|
|||
|
|
// LOG_FORMAT=json -> JSON
|
|||
|
|
//
|
|||
|
|
// The public API (type AuditLogger and all its methods) is unchanged, so no call‑sites
|
|||
|
|
// (e.g. cognito-permit-sync.go) need to be modified.
|
|||
|
|
package main
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"context"
|
|||
|
|
"log/slog"
|
|||
|
|
"os"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
const envLogFormat = "LOG_FORMAT"
|
|||
|
|
|
|||
|
|
// AuditLogger handles audit‑trail logging for compliance.
|
|||
|
|
type AuditLogger struct {
|
|||
|
|
logger *slog.Logger
|
|||
|
|
file *os.File
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// NewAuditLogger initializes the audit logger.
|
|||
|
|
// The signature is unchanged: pass isDryRun=true to write to dry-run-audit.log;
|
|||
|
|
// otherwise logs are appended to audit.log in the working directory.
|
|||
|
|
func NewAuditLogger(isDryRun bool) (*AuditLogger, error) {
|
|||
|
|
filename := "audit.log"
|
|||
|
|
if isDryRun {
|
|||
|
|
filename = "dry-run-audit.log"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
file, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Choose handler based on LOG_FORMAT
|
|||
|
|
var handler slog.Handler
|
|||
|
|
switch os.Getenv(envLogFormat) {
|
|||
|
|
case "json":
|
|||
|
|
handler = slog.NewJSONHandler(file, &slog.HandlerOptions{AddSource: false})
|
|||
|
|
default: // "text" or unset
|
|||
|
|
handler = slog.NewTextHandler(file, &slog.HandlerOptions{AddSource: false})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
logger := slog.New(handler)
|
|||
|
|
|
|||
|
|
return &AuditLogger{
|
|||
|
|
logger: logger,
|
|||
|
|
file: file,
|
|||
|
|
}, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Close closes the underlying audit file.
|
|||
|
|
func (a *AuditLogger) Close() error {
|
|||
|
|
if a.file != nil {
|
|||
|
|
return a.file.Close()
|
|||
|
|
}
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ----- Public logging helpers ------------------------------------------------
|
|||
|
|
|
|||
|
|
// ActionType represents the type of action being logged.
|
|||
|
|
type ActionType string
|
|||
|
|
|
|||
|
|
const (
|
|||
|
|
ActionCreate ActionType = "CREATE"
|
|||
|
|
ActionDelete ActionType = "DELETE"
|
|||
|
|
ActionDisable ActionType = "DISABLE"
|
|||
|
|
ActionEnable ActionType = "ENABLE"
|
|||
|
|
ActionAssignRole ActionType = "ASSIGN_ROLE"
|
|||
|
|
ActionUnassignRole ActionType = "UNASSIGN_ROLE"
|
|||
|
|
ActionUpdate ActionType = "UPDATE"
|
|||
|
|
ActionSkip ActionType = "SKIP"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// SystemType represents the system where the action occurred.
|
|||
|
|
type SystemType string
|
|||
|
|
|
|||
|
|
const (
|
|||
|
|
SystemCognito SystemType = "COGNITO"
|
|||
|
|
SystemPermit SystemType = "PERMIT"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// ResultType represents the outcome of the action.
|
|||
|
|
type ResultType string
|
|||
|
|
|
|||
|
|
const (
|
|||
|
|
ResultSuccess ResultType = "SUCCESS"
|
|||
|
|
ResultFailure ResultType = "FAILURE"
|
|||
|
|
ResultSkipped ResultType = "SKIPPED"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// LogAction logs a generic action (without subjectID or role).
|
|||
|
|
func (a *AuditLogger) LogAction(action ActionType, system SystemType, userEmail string, result ResultType, details string) {
|
|||
|
|
a.logger.InfoContext(context.TODO(), "audit_event",
|
|||
|
|
"action", action,
|
|||
|
|
"system", system,
|
|||
|
|
"userEmail", userEmail,
|
|||
|
|
"result", result,
|
|||
|
|
"details", details,
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// LogActionWithSubjectID logs an action involving a specific subject identifier.
|
|||
|
|
func (a *AuditLogger) LogActionWithSubjectID(action ActionType, system SystemType, userEmail, subjectID string, result ResultType, details string) {
|
|||
|
|
a.logger.InfoContext(context.TODO(), "audit_event",
|
|||
|
|
"action", action,
|
|||
|
|
"system", system,
|
|||
|
|
"userEmail", userEmail,
|
|||
|
|
"subjectID", subjectID,
|
|||
|
|
"result", result,
|
|||
|
|
"details", details,
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// LogRoleAction logs role assignment/unassignment activities.
|
|||
|
|
func (a *AuditLogger) LogRoleAction(action ActionType, userEmail, role string, result ResultType, details string) {
|
|||
|
|
a.logger.InfoContext(context.TODO(), "audit_event",
|
|||
|
|
"action", action,
|
|||
|
|
"system", SystemPermit,
|
|||
|
|
"userEmail", userEmail,
|
|||
|
|
"role", role,
|
|||
|
|
"result", result,
|
|||
|
|
"details", details,
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// LogDryRunStart marks the beginning of a dry‑run execution.
|
|||
|
|
func (a *AuditLogger) LogDryRunStart() {
|
|||
|
|
a.logger.InfoContext(context.TODO(), "dry_run_start")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// LogDryRunEnd marks the completion of a dry‑run execution.
|
|||
|
|
func (a *AuditLogger) LogDryRunEnd() {
|
|||
|
|
a.logger.InfoContext(context.TODO(), "dry_run_end")
|
|||
|
|
}
|