Risk analysis R2 updated (one restore now evidenced), workplan cross-referenced with the assessment's pickup queue; new T08 tracks cross-repo backup items. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
8 KiB
Initial Risk Analysis — Failure Modes for disaster-control
Date: 2026-07-04
Author: claude-code (session with Bernd)
Status: baseline — to be revisited after AssetRegister and first restore drill
Source: specs/ResilienceControlSetup.md, INTENT.md, current Coulomb/Helix stack
(Gitea, k3s, CoulombCore, Bubble.io, Stripe, OpenRouter, DNS, secrets, Ansible)
Companion: 2026-07-04-forgejo-backup-strategy-assessment.md — same-day
Forgejo/Railiance deep-dive with a concrete pickup queue for this repo
Purpose
Enumerate the failure modes the Resilience Control Plane must address, rank them, and map each to the artifact (register, policy, runbook, playbook, drill) that mitigates it. This is the justification layer for the initial workplans.
Scoring
- Likelihood L1 (rare) – L5 (expected within a year)
- Impact I1 (nuisance) – I5 (existential: money, identity, or irreplaceable data lost)
- Exposure today = how well the current setup handles it before this repo does its job
Failure modes
R1 — Full production server loss (CoulombCore)
Disk failure, VPS deletion, provider account closure, fat-fingered teardown.
L3 / I4. Exposure today: high — rebuild path exists conceptually (Ansible)
but is not documented end-to-end and has never been drilled.
Mitigation: restore runbook 01-full-server-loss, Ansible baseline as the
recovery asset, offsite encrypted backups, DNS cutover procedure, quarterly rebuild drill.
R2 — Backup exists but restore fails (untested backups)
The classic silent failure: dumps run for months, first real restore reveals
corruption, missing volumes, undumped databases, or an unknown passphrase.
L4 / I5 (it converts every other risk into a total loss). Exposure today:
high — exactly one restore has been evidenced: the 2026-07-04 Forgejo isolated
restore drill (RAIL-HO-WP-0005-T09, evidence in railiance-infra). Gitea (the
canonical source forge today), CoulombCore content, databases, Bubble exports,
and the secret vault have never been restore-tested.
Mitigation: the TestEvidence loop itself — recurring restore drills with dated
reports measuring actual RTO/RPO. This is the highest-leverage artifact in the repo.
R3 — Ransomware / hostile access deletes backups too
Attacker with production admin credentials encrypts data and deletes reachable
backups. L2 / I5. Exposure today: high if backup credentials live on the
production host with delete permission.
Mitigation: backup credential separation (BackupPolicy §credentials),
immutable/append-only offsite copy, offline weekly copy, breach-recovery runbook
(never restore into the compromised machine), secret rotation runbook.
R4 — Loss of admin identity (registrar, Stripe, Gitea, email, cloud)
Locked out via lost MFA device, expired recovery email, account takeover, or provider suspension. L2 / I5 — identity is Tier 0; without it nothing else can be recovered. Exposure today: unknown — no inventory of recovery codes, backup admins, or break-glass paths exists. Mitigation: AssetRegister T0 section with recovery paths per account, offline recovery codes, break-glass process, loss-of-admin-identity playbook.
R5 — Secrets lost or leaked
Two directions: (a) recovery material lost → backups undecryptable, services unrebuildable; (b) secret leaked → every dependent system compromised. L3 / I5. Exposure today: medium-high — OpenBao/warden infrastructure exists but sealed recovery material for disaster scenarios is not evidenced. Mitigation: encrypted (SOPS/age) sealed recovery vault backed up offline, secret-rotation runbook, credential-leak playbook. Restore drills must include "can we actually decrypt the vault from cold".
R6 — Accidental deletion / bad migration / data corruption
Deleted repo, destructive script, corrupted DB, bad Ansible run. L4 / I3 (bounded if backups have granularity and short RPO). Exposure today: medium. Mitigation: accidental-delete and data-corruption playbooks (stop writes → staging restore → identify last good point → selective restore → diff), local snapshots for fast rollback, RPO targets per system in the RTO/RPO matrix.
R7 — External provider outage or exit (Bubble, Stripe, OpenRouter, DNS, email)
Outage is L4/I2 (degradation); forced exit (provider shutdown, account ban, pricing change) is L2/I4 — especially Bubble, which holds member data on a platform we don't control. Exposure today: high for Bubble (export cadence not established), low-medium for others. Mitigation: T4 section of AssetRegister documenting export paths and limits, scheduled Bubble and Stripe exports, provider-outage playbook with graceful degradation, alternate-LLM path for OpenRouter.
R8 — DNS / domain hijack or lapse
Expired domain, registrar compromise, hostile transfer. L1 / I5. Exposure today: unknown (lock status, MFA, backup contacts uninventoried). Mitigation: registrar lock + MFA + backup admin recorded in AssetRegister, zone-record exports after changes, 2h RTO cutover procedure.
R9 — Silent backup failure (job stops, nobody notices)
Cron dies, disk fills, token expires; discovered only at restore time. L4 / I4 (degenerates into R2). Exposure today: high — no backup success monitoring is defined. Mitigation: monitoring & evidence checks (daily job-success check, weekly integrity check) defined in BackupPolicy with an explicit alerting owner.
R10 — The control plane itself is lost or stale
Two sub-modes: (a) this repo lives on the same Gitea it protects — a full-loss event takes the recovery instructions down with it; (b) docs drift from reality and runbooks silently rot. L3 / I4. Exposure today: high — repo is single-homed as of this writing. Mitigation: mirror disaster-control to at least one independent location (and one offline/printable panic sheet), monthly asset-register review, drills double as doc-verification.
R11 — Single-operator dependency (bus factor = 1)
Bernd is the only person who knows where backups are, how to rotate secrets, and holds the MFA devices. L2 / I5. Exposure today: structural. Mitigation: the panic sheet ("where backups are, who has access, how to rebuild") written so a competent stranger could execute it; offline recovery material reachable by a designated second person.
R12 — Payment/financial record loss (Stripe divergence)
Stripe holds the authoritative customer/payment state; account loss or membership-state divergence with Bubble breaks the business's money loop. L2 / I4. Exposure today: medium. Mitigation: scheduled Stripe exports (CSV or Data Pipeline) into backed-up storage, reconciliation step in provider-outage playbook.
Priority ranking (exposure × impact)
- R2 untested restores — invalidates everything else; fix via evidence loop
- R9 silent backup failure — feeds R2 directly
- R3 backup-deleting breach — credential separation is cheap and decisive
- R4/R5 identity & secrets recovery — T0, low effort to inventory, existential if wrong
- R10 control plane single-homed — mirror this repo immediately (near-zero cost)
- R1 full server loss — the flagship runbook, exercised by drills
- R7/R12 provider exports (Bubble, Stripe) — schedule and verify
- R6, R8, R11 — covered incrementally by playbooks and the panic sheet
Consequences for the workplan
- First workplan must deliver: RTO/RPO matrix + ResiliencePolicy (targets), AssetRegister/DataRegister (inventory incl. T0 recovery paths), BackupPolicy with credential-separation rules, the full-server-loss runbook, a panic sheet, and one real restore drill with an evidence file — because until R2 is exercised once, everything else is theory.
- Mirroring this repo off the primary Gitea (R10) is a day-one ad hoc task, not a workplan phase.
- Backup automation (restic, gitea dump, etcd snapshots, Bubble/Stripe export jobs) runs where the infrastructure lives; this repo tracks its policy, schedule, and evidence — see INTENT.md boundaries.