mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-10 16:04:04 +00:00
docs: complete multiplayer threat model
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
# Cosmic Clash multiplayer threat model
|
||||
|
||||
This is the launch threat model for the control plane, dedicated servers and
|
||||
clients. It records the security boundary and the verification owner for each
|
||||
class of failure; it does not treat a trusted workload class as a trusted
|
||||
individual pod.
|
||||
|
||||
| Threat | Prevention | Detection / response | Owner | Residual risk |
|
||||
|---|---|---|---|---|
|
||||
| Forged Steam identity or ticket | Backend calls Steam validation for the expected App ID; player ID comes from the verified SteamID mapping, never request JSON | Ticket rejection metrics, replay alerts, ban/revoke identity | Identity/API | Valve/Steam outage pauses new authenticated sessions |
|
||||
| Ticket/session replay | Single-use ticket nonce; opaque short-lived session token; store token digest and revocation in PostgreSQL | Duplicate-ticket and revoked-session counters; incident revoke all sessions for identity | Identity/API | Stolen live session remains usable until expiry/revocation propagation |
|
||||
| Queue/proposal flooding or duplicate claims | Body/rate limits, one active ticket partial unique index, idempotency keys, serializable participant fence | Per-identity/IP rate alerts, queue-depth and conflict dashboards, overload shedding | API/matcher | Distributed abusive identities can consume bounded capacity until automated bans act |
|
||||
| Latency-evidence forgery | Opaque location, nonce/freshness checks, server-computed RTT, discrepancy quarantine; evidence affects placement only | Three-bad/five-clean counters and regional RTT SLO alerts | Matcher/networking | Colluding endpoints can bias placement within the accepted evidence window |
|
||||
| Join-authorisation theft or slot hijack | Signed match-scoped authorisation binds verified SteamID/match/server/team/slot/protocol/expiry; server-owned generation fences old peers | Rejected-binding/generation metrics and audit events; revoke assignment | Allocator/game-server | A stolen valid authorisation remains usable until expiry unless the server revokes it |
|
||||
| Forged or replayed match result | Pod/GameServer-bound projected identity or one-match credential; issuer/audience/namespace/SA/pod/GameServer/allocator binding; canonical digest | Receipt conflict is inert and pages; duplicate is idempotent; result lag alerts at 5/30 minutes | Result/maintenance | A compromised authoritative pod can submit before compromise is detected |
|
||||
| Workload/insider compromise | Per-workload service accounts, least RBAC, private stores, default-deny network, no publisher/root key in game pods | Credential-use audit, pod identity anomaly alerts, immediate workload drain/revoke | Platform/security | Cluster-admin or KMS compromise is outside application controls |
|
||||
| Gameplay/API DDoS and flood | Connection/body/WebSocket limits, token buckets, overload shedding, edge WAF/DDoS service, live-result priority | Saturation, 5xx, tick-backlog and dropped-work dashboards; shed new queue/allocation work first | SRE/platform | Volumetric attack may require provider mitigation capacity |
|
||||
| SDR signing-key theft | Offline CA separated from online signer; non-exportable KMS/HSM key; signer allowlist and short-lived tickets | Signer audit and anomaly alerts; rotate/revoke certificates and tickets | Security/networking | Provider/Valve trust or HSM compromise requires external response |
|
||||
| Dependency/image supply chain | Pin image/dependency digests, SBOM, vulnerability scan, artifact signature and admission verification | CI/admission failures and provenance inventory; critical-fix SLA | Release/security | Unknown zero-days remain possible until detection or patch |
|
||||
| Denial of wallet / autoscaling abuse | Allocation quotas, budgets, warm-capacity limits, per-identity/IP controls and scale ceilings | Cost-per-match, allocation-rate and quota alerts; disable region/playlist safely | SRE/finance | Legitimate launch spikes can trigger conservative limits |
|
||||
| Data loss or cache inconsistency | PostgreSQL backups/RPO <=5m, serializable transactions, transactional outbox; Redis is rebuildable only | Restore/failover rehearsal, cache-repair metrics, result reconciliation | Data/SRE | Recovery can pause new work; valid live matches must continue |
|
||||
|
||||
## Trust boundaries
|
||||
|
||||
- Clients are untrusted and cannot submit ratings, outcomes, penalties,
|
||||
allocation state or exemptions.
|
||||
- Game servers are authoritative for simulation but are not trusted for
|
||||
identity, allocation ownership, or unrestricted result submission.
|
||||
- PostgreSQL is the durable authority. Redis, Agones annotations and local
|
||||
spool files are recoverable transport/cache state.
|
||||
- The offline SDR CA and online leaf signer are separate; API, matcher,
|
||||
allocator and game-server workloads cannot read signer keys.
|
||||
|
||||
Every accepted residual risk above has an owner and a planned detection path.
|
||||
Security incidents fail closed for identity/result ownership and degrade open
|
||||
only for recoverable result delivery, where the signed spool is reconciled.
|
||||
+3
-2
@@ -53,8 +53,9 @@ product policy are in [`docs/MATCHMAKING.md`](docs/MATCHMAKING.md).
|
||||
identity; make identical duplicates idempotent and conflicting results
|
||||
inert/alerting. Pure Go binding, hashing, reconciliation, and SQL boundaries exist;
|
||||
production credential validation remains.
|
||||
- [ ] Complete the threat model for forgery, replay, queue/flood/bot abuse,
|
||||
workload/insider compromise, DDoS, supply chain and denial-of-wallet.
|
||||
- [x] Complete the threat model for forgery, replay, queue/flood/bot abuse,
|
||||
workload/insider compromise, DDoS, supply chain and denial-of-wallet
|
||||
([THREAT-MODEL.md](docs/THREAT-MODEL.md)).
|
||||
- [ ] Enforce restricted workloads/RBAC/networks/private stores/backups/secrets;
|
||||
isolate SDR signing behind an audited non-exportable signer and add
|
||||
volumetric edge defense, WebSocket limits and overload shedding.
|
||||
|
||||
+1
-1
@@ -1183,7 +1183,7 @@ the local/CI/community transport, not a silent production fallback.
|
||||
| 8.8 `[D:8.7]` | **IN PROGRESS.** Pure Go session policy issues opaque short-lived tokens, stores only digests, authenticates by verified player identity and supports revocation | `server/domain/auth.go` covers wrong-token/expiry/revocation behavior; distributed revocation, account/IP limits, request limits and production session persistence remain |
|
||||
| 8.9 `[D:8.4,8.7]` | **IN PROGRESS.** Pure Go join policy binds SteamID/player/match/server/team/slot/protocol/expiry, rejects duplicate roster slots, permits same-identity reclaim through backend loss and fences prior server-owned generations | `server/domain/reconnect.go` covers SteamID/server/slot binding, expiry, repeated reclaim, grace boundary and old-generation fencing; signed token issuance/verification, persistent leases, Godot `hello` transport and production integration remain |
|
||||
| 8.10 `[D:8.5,8.31]` | Authenticate results with pod-bound projected identity or one-match attested credential; validate issuer/audience/expiry, namespace/SA, pod UID, GameServer UID and allocator match binding | Another pod sharing a workload class cannot submit for the allocation; identical duplicates are idempotent; conflicting results are inert and alerting across all trusted clusters |
|
||||
| 8.11 `[D:8.1]` | Write the threat model: forged clients/replay/queues/results, floods/bots, pod/insider compromise, gameplay and API DDoS, SDR signing-key theft, dependencies and denial-of-wallet | Every threat has prevention/detection/owner/verification; accepted residual risks are explicit; offline CA and online signer trust boundaries are separate |
|
||||
| 8.11 `[D:8.1]` | **DONE.** Write the threat model: forged clients/replay/queues/results, floods/bots, pod/insider compromise, gameplay and API DDoS, SDR signing-key theft, dependencies and denial-of-wallet | [`docs/THREAT-MODEL.md`](docs/THREAT-MODEL.md) records prevention, detection/response, owner and residual risk for every threat; it separates offline CA/online signer, client/game-server/PostgreSQL/Redis trust boundaries and recovery behavior |
|
||||
| 8.12 `[D:8.11]` | Harden workloads and edge: restricted containers, least RBAC, private DB/Redis, default-deny networks, backups/secrets, volumetric DDoS/WAF/origin shielding, WebSocket limits and overload shedding | Policy/network tests enforce declared flows; edge load test preserves result ingress/live matches while rejecting new work; no credential appears in Git/images/args/telemetry |
|
||||
| 8.13 `[D:8.12]` | Pin images by digest; generate SBOMs, scan dependencies/images, sign artifacts, verify signatures at admission and document a critical-fix SLA | CI blocks a vulnerable/disallowed or unsigned release artifact and records the exact provenance deployed |
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
from pathlib import Path
|
||||
import unittest
|
||||
|
||||
|
||||
MODEL = (Path(__file__).parents[2] / "docs" / "THREAT-MODEL.md").read_text()
|
||||
|
||||
|
||||
class ThreatModelTest(unittest.TestCase):
|
||||
def test_required_threat_classes_have_controls_and_owners(self):
|
||||
for term in (
|
||||
"Forged Steam identity", "Ticket/session replay", "Queue/proposal",
|
||||
"Latency-evidence forgery", "Join-authorisation", "Forged or replayed match result",
|
||||
"Workload/insider compromise", "DDoS", "SDR signing-key theft",
|
||||
"supply chain", "Denial of wallet / autoscaling abuse", "Data loss",
|
||||
):
|
||||
self.assertIn(term, MODEL)
|
||||
self.assertIn("| Owner |", MODEL)
|
||||
self.assertIn("Residual risk", MODEL)
|
||||
self.assertIn("PostgreSQL is the durable authority", MODEL)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user