Documentation
¶
Overview ¶
Package audit provides Servora's audit event runtime: event model, emitter interface, recorder, and Kratos middleware skeleton.
Index ¶
- Constants
- func Audit(opts ...AuditMiddlewareOption) middleware.Middleware
- type ActorInfo
- type AuditEvent
- type AuditMiddlewareOption
- type AuthnDetail
- type AuthzDecision
- type AuthzDetail
- type BrokerEmitter
- type Emitter
- type EventType
- type LogEmitter
- type NoopEmitter
- type Recorder
- func (r *Recorder) AuthnObserver() func(context.Context, authn.AuthnDetail)
- func (r *Recorder) AuthzObserver() func(context.Context, authz.DecisionDetail)
- func (r *Recorder) Close() error
- func (r *Recorder) RecordAuthnResult(ctx context.Context, operation string, a actor.Actor, detail AuthnDetail)
- func (r *Recorder) RecordAuthzDecision(ctx context.Context, operation string, a actor.Actor, detail AuthzDetail)
- func (r *Recorder) RecordResourceMutation(ctx context.Context, operation string, a actor.Actor, target TargetInfo, ...)
- func (r *Recorder) RecordTupleChange(ctx context.Context, operation string, a actor.Actor, ...)
- type ResourceMutationDetail
- type ResourceMutationType
- type ResultInfo
- type Rule
- type TargetInfo
- type TupleChange
- type TupleMutationDetail
- type TupleMutationType
Constants ¶
const DefaultAuditTopic = "servora.audit.events"
Variables ¶
This section is empty.
Functions ¶
func Audit ¶
func Audit(opts ...AuditMiddlewareOption) middleware.Middleware
Audit returns a Kratos middleware that records audit events based on configured rules. Operations with no matching rule are passed through silently.
This is a skeleton — full implementation follows in phase 2 when audit middleware is integrated with real service handlers.
Types ¶
type ActorInfo ¶
type ActorInfo struct {
ID string
Type string
DisplayName string
Email string
Subject string
ClientID string
Realm string
}
ActorInfo is an immutable snapshot of the requesting actor at event time.
type AuditEvent ¶
type AuditEvent struct {
EventID string
EventType EventType
EventVersion string
OccurredAt time.Time
Service string
Operation string
Actor ActorInfo
Target TargetInfo
Result ResultInfo
TraceID string
RequestID string
Detail any
}
AuditEvent is the Go runtime representation of an audit event. It is converted to proto for transport via BrokerEmitter.
type AuditMiddlewareOption ¶
type AuditMiddlewareOption func(*auditMiddlewareConfig)
AuditMiddlewareOption configures the audit middleware.
func WithRecorder ¶
func WithRecorder(r *Recorder) AuditMiddlewareOption
WithRecorder sets the Recorder to use for emitting events.
func WithRules ¶
func WithRules(rules map[string]Rule) AuditMiddlewareOption
WithRules sets the per-operation audit rules directly.
func WithRulesFunc ¶
func WithRulesFunc(fn func() map[string]Rule) AuditMiddlewareOption
WithRulesFunc sets the per-operation audit rules via a function (e.g. generated AuditRules()). The function is called once during middleware construction.
type AuthnDetail ¶
AuthnDetail carries authentication-specific detail.
type AuthzDecision ¶
type AuthzDecision string
AuthzDecision describes the outcome of an authorization check.
const ( AuthzDecisionAllowed AuthzDecision = "allowed" AuthzDecisionDenied AuthzDecision = "denied" AuthzDecisionNoRule AuthzDecision = "no_rule" AuthzDecisionError AuthzDecision = "error" )
type AuthzDetail ¶
type AuthzDetail struct {
Relation string
ObjectType string
ObjectID string
Decision AuthzDecision
ErrorReason string
}
AuthzDetail carries authorization-decision detail. Cache-hit metrics live in infra/openfga (engine-internal optimization), not in audit semantics.
type BrokerEmitter ¶
type BrokerEmitter struct {
// contains filtered or unexported fields
}
BrokerEmitter sends audit events to a message broker topic (e.g. Kafka). Events are proto-marshaled using api/protos/audit/v1/audit.proto.
func NewBrokerEmitter ¶
func NewBrokerEmitter(b broker.Broker, topic string, l logger.Logger) *BrokerEmitter
func (*BrokerEmitter) Close ¶
func (e *BrokerEmitter) Close() error
func (*BrokerEmitter) Emit ¶
func (e *BrokerEmitter) Emit(ctx context.Context, event *AuditEvent) error
type Emitter ¶
type Emitter interface {
// Emit sends the event to the backend. Errors are non-fatal (audit must not break business flow).
Emit(ctx context.Context, event *AuditEvent) error
// Close releases any resources held by the emitter.
Close() error
}
Emitter is the interface for sending audit events to a backend. Implementations: BrokerEmitter (→ Kafka), LogEmitter (→ logger), NoopEmitter (→ /dev/null).
type LogEmitter ¶
type LogEmitter struct {
// contains filtered or unexported fields
}
LogEmitter serialises audit events as JSON and writes them to the Servora logger. Intended for development and debug environments.
func NewLogEmitter ¶
func NewLogEmitter(l logger.Logger) *LogEmitter
func (*LogEmitter) Close ¶
func (e *LogEmitter) Close() error
func (*LogEmitter) Emit ¶
func (e *LogEmitter) Emit(_ context.Context, event *AuditEvent) error
type NoopEmitter ¶
type NoopEmitter struct{}
NoopEmitter silently discards all events. Used in tests and when audit is disabled.
func NewNoopEmitter ¶
func NewNoopEmitter() *NoopEmitter
func (*NoopEmitter) Close ¶
func (n *NoopEmitter) Close() error
func (*NoopEmitter) Emit ¶
func (n *NoopEmitter) Emit(_ context.Context, _ *AuditEvent) error
type Recorder ¶
type Recorder struct {
// contains filtered or unexported fields
}
Recorder is the primary entrypoint for producing audit events. It wires actor extraction, auto-fills metadata, and delegates to an Emitter.
func NewRecorder ¶
NewRecorder creates a Recorder backed by the given Emitter.
func NewRecorderOptional ¶
NewRecorderOptional creates a Recorder from App config. When audit is disabled or emitter_type is unrecognised, a NoopEmitter-backed Recorder is returned so callers never need a nil check.
Follows the optional-initialisation pattern of pkg/openfga.NewClientOptional.
func (*Recorder) AuthnObserver ¶ added in v0.4.3
func (r *Recorder) AuthnObserver() func(context.Context, authn.AuthnDetail)
AuthnObserver returns a callback for security/authn.Server's WithObserver option that forwards every authentication outcome to this Recorder via RecordAuthnResult.
The returned callback is nil-safe: when invoked on a nil *Recorder, it is a no-op, allowing business code to wire an observer unconditionally without first nil-checking the recorder.
Field mapping (security/authn.AuthnDetail → audit.AuthnDetail):
- Method → Method (verbatim)
- Allowed → Success
- Err.Error() → FailureReason (empty string when Err == nil)
Subject (actor.Actor) is passed as the audit Actor; Operation is resolved from the request transport (empty when no transport).
func (*Recorder) AuthzObserver ¶ added in v0.4.3
func (r *Recorder) AuthzObserver() func(context.Context, authz.DecisionDetail)
AuthzObserver returns a callback for security/authz.Server's WithObserver option that forwards every Check decision to this Recorder via RecordAuthzDecision.
The returned callback is nil-safe: when invoked on a nil *Recorder, it is a no-op.
Decision mapping (authz.DecisionDetail → audit.AuthzDetail.Decision):
- d.Err != nil → AuthzDecisionError
- d.Allowed → AuthzDecisionAllowed
- !d.Allowed → AuthzDecisionDenied
The audit Actor is extracted from ctx via actor.FromContext (mirroring the previous bridge.go behavior); fall back to anonymous when not set.
func (*Recorder) RecordAuthnResult ¶
func (r *Recorder) RecordAuthnResult(ctx context.Context, operation string, a actor.Actor, detail AuthnDetail)
RecordAuthnResult records an authentication attempt result.
func (*Recorder) RecordAuthzDecision ¶
func (r *Recorder) RecordAuthzDecision(ctx context.Context, operation string, a actor.Actor, detail AuthzDetail)
RecordAuthzDecision records an OpenFGA authorization check result.
func (*Recorder) RecordResourceMutation ¶
func (r *Recorder) RecordResourceMutation(ctx context.Context, operation string, a actor.Actor, target TargetInfo, detail ResourceMutationDetail, err error)
RecordResourceMutation records a CRUD operation on a business resource.
func (*Recorder) RecordTupleChange ¶
func (r *Recorder) RecordTupleChange(ctx context.Context, operation string, a actor.Actor, detail TupleMutationDetail)
RecordTupleChange records an OpenFGA tuple write or delete.
type ResourceMutationDetail ¶
type ResourceMutationDetail struct {
MutationType ResourceMutationType
ResourceType string
ResourceID string
}
ResourceMutationDetail carries CRUD-operation detail.
type ResourceMutationType ¶
type ResourceMutationType string
ResourceMutationType describes the type of resource mutation.
const ( ResourceMutationCreate ResourceMutationType = "create" ResourceMutationUpdate ResourceMutationType = "update" ResourceMutationDelete ResourceMutationType = "delete" )
type ResultInfo ¶
ResultInfo captures the outcome of the audited operation.
type Rule ¶
type Rule struct {
// EventType is the audit event type to emit.
EventType EventType
// Operation override (defaults to the gRPC operation path).
Operation string
// TargetType is the resource type being operated on (e.g. "user").
TargetType string
// MutationType specifies the mutation kind (create/update/delete) for
// EventTypeResourceMutation rules. Defaults to ResourceMutationUpdate if unset.
MutationType ResourceMutationType
// RecordOnError controls whether to emit events even when the handler fails.
RecordOnError bool
// TargetIDFunc extracts the target resource ID from the request/response.
// Generated by protoc-gen-servora-audit for rules with target_id_field set.
// Called after handler returns; req is the original request, resp is the handler response.
TargetIDFunc func(req, resp any) string
}
Rule describes how a specific RPC operation should be audited.
type TargetInfo ¶
TargetInfo describes the resource the action was performed on.
type TupleChange ¶
TupleChange describes a single OpenFGA tuple change.
type TupleMutationDetail ¶
type TupleMutationDetail struct {
MutationType TupleMutationType
Tuples []TupleChange
}
TupleMutationDetail carries OpenFGA tuple-write/delete detail.
type TupleMutationType ¶
type TupleMutationType string
TupleMutationType describes the type of tuple change.
const ( TupleMutationWrite TupleMutationType = "write" TupleMutationDelete TupleMutationType = "delete" )