Record automated Forgejo backup decrypt drill evidence, update registers and pickup queue (item 3 in progress). Mark WP-0002 finished — 8/8 tasks done.
482 lines
No EOL
16 KiB
YAML
482 lines
No EOL
16 KiB
YAML
# Resilience Control Plane — asset register (initial seed)
|
|
# DISCTL-WP-0003-T01 — railiance-backup tool family and backup lanes
|
|
# Backup lanes: DISCTL-WP-0003-T01. Stack assets (T0/T4): DISCTL-WP-0002-T02.
|
|
|
|
schema_version: "0.2"
|
|
updated: "2026-07-07"
|
|
register_scope: backup_lanes_and_stack
|
|
|
|
tier_definitions:
|
|
T0: "Identity / trust / money — recoverable even after breach"
|
|
T1: "Irreplaceable source of truth — strong backups, tested restore"
|
|
T2: "Runtime platforms — rebuild from IaC + restore data"
|
|
T3: "Derived / rebuildable — recompute where possible"
|
|
T4: "External dependencies — export, monitor, document limits"
|
|
|
|
backup_streams:
|
|
- id: backup-dev-workstation
|
|
name: Dev workstation custodian state
|
|
tool: railiance-backup
|
|
tool_path: railiance-cluster/tools/cmd/railiance-backup
|
|
owner_repo: railiance-cluster
|
|
operator: Bernd
|
|
tier: T1
|
|
host: bnt-lap001
|
|
backup_mechanism: >-
|
|
pg_dump from Docker container infra-postgres-1 (custodian DB);
|
|
tar of ~/.claude, ~/.claude.json, ~/.gitconfig; age encrypt; upload via curl PUT
|
|
destination:
|
|
primary: Nextcloud WebDAV file drop (off-node)
|
|
local_cache: ~/.cache/railiance/backups/
|
|
backup_schedule: "daily 02:00 UTC (cron)"
|
|
retention: "7 local copies per artifact type"
|
|
encryption: age
|
|
recovery_method: >-
|
|
Download artifacts from Nextcloud; age -d with ~/.config/age/railiance-backup.key;
|
|
restore PostgreSQL volume; unpack config tar. See railiance-cluster/docs/backup-restore.md
|
|
rpo: 24h
|
|
rto: 4h
|
|
status: operational
|
|
gaps: []
|
|
evidence:
|
|
restore_tested: false
|
|
last_drill: null
|
|
references:
|
|
- railiance-cluster/docs/backup-restore.md
|
|
- railiance-cluster/tools/cmd/railiance-backup
|
|
|
|
- id: backup-s1-os-config
|
|
name: S1 OS and provisioning config
|
|
tool: railiance-backup-s1
|
|
tool_path: railiance-infra/tools/cmd/railiance-backup-s1
|
|
owner_repo: railiance-infra
|
|
operator: Bernd
|
|
tier: T2
|
|
host: railiance01
|
|
backup_mechanism: >-
|
|
Tar of Ansible-managed OS files (sshd, ufw, fail2ban, hosts, hostname,
|
|
apt sources) plus dpkg --get-selections; age encrypt
|
|
destination:
|
|
primary: /opt/backup/railiance/infra/ (on-node local only)
|
|
offsite: none
|
|
backup_schedule: manual (make backup in railiance-infra)
|
|
retention: "7 local copies per artifact type"
|
|
encryption: age (SOPS key pair)
|
|
recovery_method: >-
|
|
age -d with ~/.config/sops/age/keys.txt; restore files to /etc/ or re-apply
|
|
via Ansible playbooks
|
|
rpo: 24h
|
|
rto: 4-8h
|
|
status: operational
|
|
gaps:
|
|
- "No scheduled automation — manual make backup only"
|
|
- "No off-cluster upload — lost if host is destroyed"
|
|
evidence:
|
|
restore_tested: false
|
|
last_drill: null
|
|
references:
|
|
- railiance-infra/tools/cmd/railiance-backup-s1
|
|
|
|
- id: backup-s2-k8s-runtime
|
|
name: S2 Kubernetes runtime state
|
|
tool: railiance-backup-s2
|
|
tool_path: railiance-cluster/tools/cmd/railiance-backup-s2
|
|
owner_repo: railiance-cluster
|
|
operator: Bernd
|
|
tier: T1
|
|
host: railiance01
|
|
backup_mechanism: >-
|
|
sqlite3 hot backup of k3s state.db; tar of Helm release values (all namespaces);
|
|
kubeconfig copy; age encrypt
|
|
destination:
|
|
primary: /opt/backup/railiance/cluster/ (on-node local only)
|
|
offsite: none
|
|
backup_schedule: manual (make backup in railiance-cluster)
|
|
retention: "7 local copies per artifact type"
|
|
encryption: age (SOPS key pair)
|
|
recovery_method: >-
|
|
age -d; restore k3s state.db or redeploy from Helm values + kubeconfig.
|
|
Prefer rebuild-from-manifests where possible.
|
|
rpo: 24h
|
|
rto: 4-8h
|
|
status: operational
|
|
gaps:
|
|
- "No scheduled automation — manual make backup only"
|
|
- "No off-cluster upload — lost if host is destroyed"
|
|
evidence:
|
|
restore_tested: false
|
|
last_drill: null
|
|
references:
|
|
- railiance-cluster/tools/cmd/railiance-backup-s2
|
|
- history/2026-07-04-forgejo-backup-strategy-assessment.md
|
|
|
|
- id: backup-s3-platform
|
|
name: S3 platform services (PostgreSQL, Valkey)
|
|
tool: railiance-backup
|
|
tool_path: railiance-platform/tools/cmd/railiance-backup
|
|
owner_repo: railiance-platform
|
|
operator: Bernd
|
|
tier: T1
|
|
host: railiance01
|
|
backup_mechanism: >-
|
|
Intended pg_dump of platform PostgreSQL HA and Valkey state; age encrypt;
|
|
upload to Nextcloud WebDAV (same lane as dev workstation pattern)
|
|
destination:
|
|
primary: Nextcloud WebDAV file drop (intended, off-node)
|
|
local_cache: TBD
|
|
backup_schedule: TBD
|
|
retention: "14 daily + 4 weekly rotations (adopted 2026-07-09 for Forgejo lane)"
|
|
encryption: age
|
|
recovery_method: >-
|
|
Not operational — tool absent. Makefile target exists but
|
|
tools/cmd/railiance-backup was never relocated from railiance-cluster
|
|
(RAIL-PL-WP-0001-T05 cancelled).
|
|
rpo: 24h
|
|
rto: 4h
|
|
status: missing
|
|
gaps:
|
|
- "tools/cmd/railiance-backup absent from railiance-platform"
|
|
- "make backup target references missing implementation"
|
|
- "Relocation from railiance-cluster planned but never completed"
|
|
evidence:
|
|
restore_tested: false
|
|
last_drill: null
|
|
references:
|
|
- railiance-platform/Makefile
|
|
- railiance-platform/docs/postgresql-ha.md
|
|
- history/2026-07-04-forgejo-backup-strategy-assessment.md
|
|
|
|
- id: backup-forgejo-production
|
|
name: Forgejo production (git, packages, DB)
|
|
tool: forgejo dump + CNPG pg_dump
|
|
tool_path: null
|
|
owner_repo: railiance-platform
|
|
operator: Bernd
|
|
tier: T1
|
|
host: railiance01
|
|
backup_mechanism: >-
|
|
Daily forgejo dump zip (repos, packages OCI/npm/generic, attachments, LFS,
|
|
avatars) plus daily pg_dump from CNPG forgejo-db; age encrypt; Nextcloud upload
|
|
destination:
|
|
primary: Nextcloud WebDAV file drop (decided 2026-07-09, not wired)
|
|
drill_archive: workstation /tmp only (T09 drill)
|
|
backup_schedule: daily 02:15 UTC cron (make forgejo-backup)
|
|
retention: "14 daily + 4 weekly rotations"
|
|
encryption: age (platform backup public key)
|
|
recovery_method: >-
|
|
forgejo-restore-drill.sh — unzip dump, copy files, psql import, isolated Helm
|
|
deploy. Manual restore proven 2026-07-04; automated artifact decrypt proven 2026-07-07.
|
|
rpo: 24h
|
|
rto: 4h
|
|
status: operational
|
|
gaps:
|
|
- "Promotion gate: 7 consecutive daily successes + restore from Nextcloud artifact (not local cache)"
|
|
- "No CNPG ScheduledBackup CR on forgejo-db (Phase 1 uses logical pg_dump)"
|
|
evidence:
|
|
restore_tested: true
|
|
last_drill: "2026-07-07"
|
|
evidence_ref: TestEvidence/restore-drill-2026-07-07-forgejo-automated.md
|
|
references:
|
|
- the-custodian/docs/forgejo-production-decisions.md
|
|
- railiance-infra/tools/forgejo-restore-drill.sh
|
|
- history/2026-07-04-forgejo-backup-strategy-assessment.md
|
|
|
|
- id: backup-gitea-canonical
|
|
name: Gitea canonical source forge (pre-cutover)
|
|
tool: gitea dump / git mirror
|
|
tool_path: null
|
|
owner_repo: railiance-infra
|
|
operator: Bernd
|
|
tier: T1
|
|
host: coulombcore
|
|
backup_mechanism: >-
|
|
Manual gitea dump before migration waves; git mirror to offsite provider (intended).
|
|
Bundled PostgreSQL + gitea-shared-storage PVC; no automated CronJob evidenced.
|
|
destination:
|
|
primary: none automated
|
|
mirror: TBD (GitHub private mirror or secondary host)
|
|
backup_schedule: pre-cutover manual only
|
|
retention: point-in-time of last manual dump
|
|
encryption: not standardized
|
|
recovery_method: gitea dump restore per Gitea docs; safety contract requires fresh
|
|
dump before each Forgejo migration wave
|
|
rpo: 24h
|
|
rto: 4-8h
|
|
status: at_risk
|
|
gaps:
|
|
- "No automated Gitea backup CronJob on coulombcore"
|
|
- "Package blob backup not evidenced"
|
|
- "Other coulomb/* repos on Gitea may lack Forgejo mirrors"
|
|
evidence:
|
|
restore_tested: false
|
|
last_drill: null
|
|
references:
|
|
- history/2026-07-04-forgejo-backup-strategy-assessment.md
|
|
- specs/ResilienceControlSetup.md
|
|
|
|
assets:
|
|
# ── T0 Identity / trust / money ──────────────────────────────────────────────
|
|
|
|
- id: asset-dns-coulomb-social
|
|
name: coulomb.social DNS zone
|
|
tier: T0
|
|
owner: Bernd
|
|
provider: IONOS
|
|
hosts:
|
|
- gitea.coulomb.social
|
|
- forgejo.coulomb.social
|
|
- hub.coulomb.social
|
|
- reuse.coulomb.social
|
|
production_ips:
|
|
coulombcore_legacy: "92.205.130.254"
|
|
railiance01: "92.205.62.239"
|
|
recovery_path:
|
|
method: IONOS control panel + zone record export
|
|
backup_admin: unknown
|
|
mfa_recovery: unknown
|
|
break_glass: unknown
|
|
backup: manual export after changes
|
|
status: at_risk
|
|
gaps:
|
|
- "Registrar lock status not inventoried"
|
|
- "MFA recovery codes not recorded here"
|
|
- "No automated zone export"
|
|
|
|
- id: asset-registrar-ionos
|
|
name: Domain registrar (IONOS)
|
|
tier: T0
|
|
owner: Bernd
|
|
recovery_path:
|
|
method: IONOS account login
|
|
backup_admin: unknown
|
|
mfa_recovery: unknown
|
|
break_glass: unknown
|
|
status: unknown
|
|
gaps:
|
|
- "Backup admin contact not recorded"
|
|
- "Account lock + MFA recovery not evidenced"
|
|
|
|
- id: asset-email-ionos
|
|
name: coulomb.social email (IONOS SMTP)
|
|
tier: T0
|
|
owner: Bernd
|
|
mailboxes:
|
|
- forgejo@coulomb.social
|
|
recovery_path:
|
|
method: IONOS mail control panel
|
|
backup_admin: unknown
|
|
mfa_recovery: unknown
|
|
status: operational
|
|
gaps:
|
|
- "Recovery path not fully documented"
|
|
|
|
- id: asset-stripe-admin
|
|
name: Stripe account (payments / subscriptions)
|
|
tier: T0
|
|
owner: Bernd
|
|
recovery_path:
|
|
method: Stripe dashboard login
|
|
backup_admin: unknown
|
|
mfa_recovery: unknown
|
|
break_glass: unknown
|
|
backup: scheduled CSV export (not established)
|
|
status: at_risk
|
|
gaps:
|
|
- "No scheduled export evidenced"
|
|
- "Recovery contacts not inventoried"
|
|
|
|
- id: asset-openbao-recovery
|
|
name: OpenBao sealed recovery material
|
|
tier: T0
|
|
owner: Bernd
|
|
host: railiance01
|
|
recovery_path:
|
|
method: OpenBao unseal keys + root token recovery procedure
|
|
backup_admin: Bernd
|
|
break_glass: ops-warden / railiance-platform runbooks
|
|
backup: SOPS/age sealed vault (not fully evidenced for cold disaster)
|
|
status: at_risk
|
|
gaps:
|
|
- "Cold disaster recovery of unseal material not drill-tested"
|
|
references:
|
|
- railiance-platform/docs/openbao-*.md
|
|
|
|
- id: asset-age-backup-keys
|
|
name: age encryption keys (backup artifacts)
|
|
tier: T0
|
|
owner: Bernd
|
|
recovery_path:
|
|
method: Password manager recovery copy
|
|
operational: ~/.config/age/railiance-backup.key, ~/.config/sops/age/keys.txt
|
|
backup: password manager (mandatory)
|
|
status: operational
|
|
gaps:
|
|
- "Password manager copy not verified in register drill"
|
|
|
|
- id: asset-backup-offsite-lane
|
|
name: Nextcloud backup file drop
|
|
tier: T0
|
|
owner: Bernd
|
|
recovery_path:
|
|
method: Nextcloud admin read access for restore; upload via filesdrop token
|
|
credentials: OpenBao platform/workloads/railiance/backup/offsite-lane
|
|
backup: N/A (this is the backup destination)
|
|
status: operational
|
|
references:
|
|
- BackupPolicy.md §4
|
|
- railiance-cluster/docs/backup-restore.md
|
|
|
|
- id: asset-ssh-warden
|
|
name: SSH certificate access (ops-warden)
|
|
tier: T0
|
|
owner: Bernd
|
|
recovery_path:
|
|
method: warden sign / cert_command
|
|
break_glass: ops-warden wiki
|
|
status: operational
|
|
references:
|
|
- AGENTS.md credential routing
|
|
|
|
# ── T1 Irreplaceable source of truth ─────────────────────────────────────────
|
|
|
|
- id: asset-gitea-canonical
|
|
name: Gitea instance (canonical forge until cutover)
|
|
tier: T1
|
|
owner: Bernd
|
|
host: coulombcore
|
|
url: https://gitea.coulomb.social
|
|
backup_stream: backup-gitea-canonical
|
|
recovery_path:
|
|
method: gitea dump restore; git mirror
|
|
status: at_risk
|
|
|
|
- id: asset-forgejo-production
|
|
name: Forgejo instance (production forge)
|
|
tier: T1
|
|
owner: Bernd
|
|
host: railiance01
|
|
url: https://forgejo.coulomb.social
|
|
backup_stream: backup-forgejo-production
|
|
recovery_path:
|
|
method: forgejo-restore-drill.sh
|
|
status: not_wired
|
|
|
|
- id: asset-git-repos
|
|
name: Git repositories (all coulomb/* repos)
|
|
tier: T1
|
|
owner: Bernd
|
|
source_of_truth: Gitea (migrating to Forgejo)
|
|
backup: git push to remote; forgejo/gitea dump for full fidelity
|
|
recovery_path:
|
|
method: git clone from mirror or dump restore
|
|
status: operational
|
|
gaps: []
|
|
|
|
- id: asset-state-hub
|
|
name: Custodian State Hub
|
|
tier: T1
|
|
owner: Bernd
|
|
host: bnt-lap001 (dev workstation)
|
|
backup_stream: backup-dev-workstation
|
|
recovery_path:
|
|
method: PostgreSQL restore from age-decrypted dump
|
|
status: operational
|
|
|
|
- id: asset-disaster-control
|
|
name: disaster-control repo (this control plane)
|
|
tier: T1
|
|
owner: Bernd
|
|
host: gitea.coulomb.social
|
|
mirror:
|
|
url: https://forgejo.coulomb.social/coulomb/disaster-control
|
|
host: railiance01
|
|
remote: forgejo-remote:coulomb/disaster-control.git
|
|
backup: git push to origin + mirror sync
|
|
recovery_path:
|
|
method: git clone from Forgejo mirror; see docs/mirror-sync.md
|
|
backup_schedule: after each push to origin (./tools/sync-mirror.sh)
|
|
status: operational
|
|
references:
|
|
- docs/mirror-sync.md
|
|
- tools/sync-mirror.sh
|
|
|
|
# ── T2 Runtime platforms ─────────────────────────────────────────────────────
|
|
|
|
- id: asset-coulombcore
|
|
name: CoulombCore server
|
|
tier: T2
|
|
owner: Bernd
|
|
host: coulombcore
|
|
ip: "92.205.130.254"
|
|
recovery_path:
|
|
method: Rebuild from Ansible + restore data; do not resurrect compromised host
|
|
backup_stream: backup-gitea-canonical
|
|
status: operational
|
|
|
|
- id: asset-railiance01
|
|
name: railiance01 k3s cluster
|
|
tier: T2
|
|
owner: Bernd
|
|
host: railiance01
|
|
ip: "92.205.62.239"
|
|
recovery_path:
|
|
method: Ansible baseline + Helm redeploy + data restore from backups
|
|
backup_streams:
|
|
- backup-s1-os-config
|
|
- backup-s2-k8s-runtime
|
|
status: operational
|
|
gaps:
|
|
- "S1/S2 backups on-node only"
|
|
|
|
# ── T4 External dependencies ─────────────────────────────────────────────────
|
|
|
|
- id: asset-bubble-io
|
|
name: Bubble.io legacy application
|
|
tier: T4
|
|
owner: Bernd
|
|
recovery_path:
|
|
method: Bubble database export + documented restore workflow
|
|
limits: Platform-controlled; export cadence not established
|
|
backup: none automated
|
|
rpo: 24h
|
|
rto: 24h
|
|
status: at_risk
|
|
gaps:
|
|
- "No scheduled export evidenced"
|
|
- "Member data on platform we do not control"
|
|
|
|
- id: asset-openrouter
|
|
name: OpenRouter API (LLM inference)
|
|
tier: T4
|
|
owner: Bernd
|
|
recovery_path:
|
|
method: Alternate LLM provider; API key rotation via OpenBao
|
|
limits: No data RPO unless storing prompts/results
|
|
backup: API keys in OpenBao
|
|
rpo: N/A
|
|
rto: 1-4h
|
|
status: operational
|
|
gaps:
|
|
- "Alternate provider path not documented in runbook"
|
|
|
|
related_streams:
|
|
# Operational on cluster but outside T01 minimum table — tracked for completeness.
|
|
- id: backup-adjacent-sso
|
|
name: Adjacent SSO/MFA stack
|
|
tools:
|
|
- privacyidea-backup
|
|
- authelia-backup
|
|
- lldap-backup
|
|
owner_repo: railiance-platform
|
|
tier: T2
|
|
host: railiance01
|
|
backup_schedule: daily CronJobs on railiance01
|
|
status: operational
|
|
note: "Only scheduled backup CronJobs found on cluster as of 2026-07-04 assessment"
|
|
|
|
- id: backup-apps-pg
|
|
name: apps-pg shared CloudNativePG cluster
|
|
owner_repo: railiance-platform
|
|
tier: T1
|
|
status: not_wired
|
|
note: "Documented follow-up in railiance-platform/docs/apps-pg.md; no ScheduledBackup CR" |