Campaign Authorization Audit and Telemetry
Purpose
Define how authorization outcomes are represented for operational auditing.
Domain events remain the immutable source of truth for successful state mutations. Authorization decisions that do not produce a domain event (especially denies) must be captured as telemetry.
Data Sources
Domain Event Journal
Use campaign domain events for:
- Successful mutations (
participant.updated,character.updated, etc.). - Actor/request correlation (
actor_type,actor_id,request_id,invocation_id).
Do not emit domain events for denied authorization attempts.
Telemetry Events
Use telemetry events for:
- Authorization allow/deny outcomes at the write authorization boundary.
- Override outcomes (for example platform
ADMINbreak-glass) when present. - Internal authorization evaluation failures (dependency/read errors).
Canonical Telemetry Event
event_name:telemetry.authz.decision
Package Ownership
telemetry.authz.decisionand related game-facing audit events are now owned by the game service ininternal/services/game/observability/audit.- Runtime emission points are the game gRPC interceptor (
GRPCRead/GRPCWrite) and game authorization policy helpers (AuthzDecision). - Stable event names remain
telemetry.*for downstream dashboard compatibility while the owning package is now game-specific.
Required attributes:
-
decision:allowdenyoverride reason_code: stable machine-readable reason codepolicy_action: normalized policy action labelgrpc_code: gRPC status code (OK,PermissionDenied, etc.)
Conditional required attributes:
override_reason: non-empty whendecision=override
Recommended attributes:
campaign_access: resolved actor campaign access (owner|manager|member)actor_user_id: resolved user identifier when availablecharacter_id,participant_id,target_*: target resource identifiers when applicableparticipant_operation: participant-governance operation label when suppliedtarget_owns_active_characters: boolean invariant signal for participant removal checks
Envelope fields should always include:
campaign_idactor_typeactor_idrequest_idinvocation_idtrace_idspan_idtimestamp
Reason Code Policy
Reason codes must be stable and backward-compatible for dashboards and alert rules.
Current baseline set:
AUTHZ_ALLOW_ACCESS_LEVELAUTHZ_ALLOW_ADMIN_OVERRIDEAUTHZ_ALLOW_RESOURCE_OWNERAUTHZ_DENY_ACCESS_LEVEL_REQUIREDAUTHZ_DENY_MISSING_IDENTITYAUTHZ_DENY_ACTOR_NOT_FOUNDAUTHZ_DENY_NOT_RESOURCE_OWNERAUTHZ_DENY_TARGET_IS_OWNERAUTHZ_DENY_LAST_OWNER_GUARDAUTHZ_DENY_MANAGER_OWNER_MUTATION_FORBIDDENAUTHZ_DENY_TARGET_OWNS_ACTIVE_CHARACTERSAUTHZ_ERROR_DEPENDENCY_UNAVAILABLEAUTHZ_ERROR_ACTOR_LOADAUTHZ_ERROR_OWNER_RESOLUTION
Runtime override signaling (game gRPC write auth boundary):
x-fracturing-space-platform-role: ADMINx-fracturing-space-authz-override-reason: <non-empty reason>
Query and Operations Guidance
Primary operational queries:
- Deny rate by
policy_actionandreason_code. - Internal-error rate (
reason_codeprefixedAUTHZ_ERROR_). - Top actors and campaigns by deny count.
- Override usage counts and reasons (when override paths are enabled).
Operational recommendations:
- Alert on sustained spikes in
AUTHZ_ERROR_*. - Track rollout by monitoring deny distributions before/after policy changes.
- Keep dashboards keyed by
reason_codeandpolicy_action, not free-text messages.