Skip to content

Kontinuum Node — Operations

Server-side storage, replication, lifecycle, admin surfaces, threat model, DR plan.

Audience: node operators, DevOps, SRE, security review.

Связанные документы:

  • architecture.md — overview / glossary / tier model — start here
  • protocols.md — DHT / mailbox / inter-node wire protocols
  • app-integration.md — client-side flows that interact с этими operations (PRO lapse, pairing, etc.)
  • pricing.md — billing model affecting cert lifecycle и replication

Section codes (§7, §9, §12, §15.1, §16) preserved from единой v0.6 спеки. §7.3 family-mode UX, §9.5 user pins UX, §15.2 app-side control — в app-integration.md.


7. Слой хранения

7.1 S3-gateway через embedded rustfs

S3-compatible endpoint реализован на embedded rustfs.

Client (kontinuum-app::clouds::S3) ─┐

                  ┌─────────────────────────┐
                  │ Auth shim (Ed25519)     │
                  └────────────┬────────────┘

                  ┌─────────────────────────┐
                  │ rustfs (presigned URLs) │
                  └────────────┬────────────┘

                  ┌─────────────────────────┐
                  │ FS backend + quota mgmt │
                  └─────────────────────────┘

Модель аутентификации:

  • AWS SigV4 не используется.
  • Client: POST /presign { operation, key, signature_over_request } с Ed25519 подписью.
  • Shim проверяет подпись, верифицирует permission, генерит 60-секундный rustfs presigned URL.
  • Client использует URL для GET/PUT/DELETE напрямую к rustfs.

Раскладка namespace:

  • Bucket: cnt-${identity_id_short} (per identity).
  • Key: ${space_id}/${blake3_hash}.
  • Иммутабельные blob'ы (CAS by hash).

Fallback strategy: если rustfs окажется недостаточно стабильным — самописный handler ~1000 строк Rust. Решение откладывается до этапа прототипа.

7.2 Relay-node как coordination + free S3

Купленный relay-node содержит:

  • DHT shard для Spaces владельца (~2-3 GB)
  • Mailbox владельца (TTL'd queue)
  • Cache transit blob'ов (resume uploads, thumbnails, streaming, ~2-3 GB)
  • System reserved (~2 GB)
  • Остаток свободного местабесплатный S3 для владельца (входит в стоимость relay-node)

Пример распределения 20GB VPS:

2 GB  system reserved
3 GB  DHT records
3 GB  transit cache
12 GB free S3 (бесплатно для владельца, в Virtual S3 Pool)

S3-bucket покупается сверх этого бесплатного только если 12GB мало или хочется geo-divergent копия в другом провайдере.

Capabilities на relay-node: dht_routing (mandatory), relay, mailbox, s3_gateway, anti_entropy, rendezvous — все default ON для tenant'а (владельца + опционально whitelisted family/team).

7.3 Family / team mode (multi-tenancy на byo-ноде)

PRO-пользователь может расшарить свою ноду (VPS или home server) с whitelisted identities как byo:* × multi.

Правила:

  • Оплачивает только владелец ноды. Tenants ничего не платят, не имеют billing-отношений с org.
  • Whitelist по identity_id — owner добавляет/удаляет вручную в PRO admin UI.
  • Per-tenant квота на storage и mailbox — задаёт owner.
  • Tenant имеет полный S3 + DHT + mailbox на этой ноде в пределах квоты, как будто это его собственная single-tenant нода.
  • Trust model: tenant trust'ит owner'а не злоупотреблять. E2E защищает от чтения данных, но не от DoS / capricious shutdown. Это family/team use case, не публичный hosting.
  • Revenue share отсутствует. Это «family plan», не reseller marketplace.

7.4 Virtual S3 Pool

App видит один логический pool — сумма всех S3-источников владельца, агрегированных в единое пространство.

Источники:

Bucket typeОписаниеCostCDN
LocalRelayFreeFree S3 на собственных relay-нодах (§7.2)бесплатно
OrgPaidS3-quota купленная у orgGB-month + egressoptional
OrgPaidWithCDNS3-quota у org + CDN-tierдороже GB + дешевле egressда
ExternalPROExternal bucket (Backblaze / R2 / AWS), прикручен в PROпрямой billing провайдеру
ExternalPROwithCDNExternal provider с CDN-front (Cloudflare R2, Bunny.net)прямой billingда

UX:

  • Space привязывается к pool с лимитом max_bytes, не к конкретному bucket'у.
  • User не выбирает bucket вручную; placement-algorithm работает за него.

Placement-algorithm:

  1. Priority 1: LocalRelayFree (бесплатно) — пока есть место.
  2. Priority 2: OrgPaid — если geo-zone подходит и есть квота.
  3. Priority 3: ExternalPRO — если PRO с прикрученными external.
  4. Внутри priority — geo-aware: предпочтение bucket'ам в нужной geo-zone.
  5. Если у blob'a высокий read-rate (thumbnails, streaming) → предпочтение *WithCDN.

Per-blob mapping blob_hash → physical_bucket хранится в Space DHT.

7.5 Матрица External vs Internal storage

ПользовательPrimary storageCoordination/cache
Free-tierТолько локально на собственных устройствах
Standard + relayЛокально + Free S3 на relay-нодеСобственная relay-node
Standard + S3-quotaOrg-managed S3 в Virtual PoolСобственная relay-node (если куплена)
PRO (subscription)Собственный external S3 в Virtual PoolСобственная(ые) attached VPS / home server
PRO + family-mode+ расшарено с whitelisted identities+ multi-tenant квоты

9. Репликация и geo-политика

9.1 Durability tiers по типу storage

Разные источники в Virtual S3 Pool дают разный уровень durability. Это явный design choice — free-tier не равен paid-tier по гарантиям.

Storage sourceDurability guaranteeЗащита от чего
LocalRelayFreeBest-effort (single-node rustfs, нет RF)Только software corruption; SSD-fail = loss
OrgPaid / OrgPaidWithCDN11-девяток (cloud-провайдер встроенно)Disk-fail, регион-outage в пределах провайдера
ExternalPRO*11-девяток (cloud-провайдер встроенно)Disk-fail, регион-outage в пределах провайдера
Cross-provider replica+ защита от outage конкретного провайдераWhole-provider blackout
Cross-region replica+ защита от регионального outageRegional disaster
Friend-replication (§9.3)Bonus copy в чужом Tier 1/2Survives non-payment владельца

Critical: LocalRelayFree приоритезируется placement-algorithm (§7.4) как cheap-tier для frequently-accessed данных, но не подходит для durability-critical content.

Рекомендация в UX: для важного контента user должен pin (§9.5) — это форсирует копию в OrgPaid / ExternalPRO (11 девяток) в дополнение к LocalRelayFree.

replication_factor в нашем смысле = «в скольких разных провайдерах / регионах хранится копия», а не «сколько физических блоков».

9.2 Размещение копий

Для Space:

  • Tier 1/2 нода владельца = mandatory replica #1 (через LocalRelayFree).
  • Дополнительные копии (по желанию владельца):
    • В другом провайдере той же geo-zone — защита от провайдер-failure.
    • В другом geo-zone — защита от regional outage / DR.
  • Размещение управляется placement-algorithm Virtual Pool (§7.4).

9.3 Friend-replication бонус

Когда identity участвует в Shared Space — её Tier 1/2 ноды автоматически становятся secondary replicas для blob'ов этого Space.

  • ✅ улучшает durability бесплатно (за счёт чужой оплаченной инфры)
  • ✅ обеспечивает выживание контента при non-payment владельца (см. §12)
  • ✅ снижает latency для участников из других регионов

9.4 Geo-zone

Geo-zone — строка из enum (eu-west, eu-east, us-east, us-west, ap-east, ap-south, ...). Атрибут не ноды, а двух разных уровней — потому что один account у провайдера может иметь bucket'ы в разных регионах:

  • host_geo_zone — где физически работает compute (VPS / home server). Атрибут node:{node_id} записи.
  • storage_geo_zone — где физически хранятся blob'ы. Атрибут per-bucket в Virtual S3 Pool.

Для single-region provider'ов (Hetzner отдельная локация, home server) host_geo_zone == storage_geo_zone. Для multi-region provider'ов (Cloudflare R2 / Backblaze / AWS S3) одна нода может иметь bucket'ы в разных регионах:

ProviderРегионыТип
AWS S3us-east-1, us-west-2, eu-west-1, ap-south-1, ...Storage
Backblaze B2us-west, eu-centralStorage
Cloudflare R2global (CDN edges)Storage
Hetznerde-fsn1, de-nbg1, fi-hel1Compute
OVHeu-fra1, eu-rbx1, ca-bhs1Compute
DigitalOceannyc1, ams3, sgp1, ...Compute

Placement-algorithm учитывает per-bucket zone (не per-node) при cross-region replica decisions.

Более тонкая стратегия (latency-aware, regulatory-aware) — open question, defer.

9.6 Blob pin record

rust
struct BlobPin {
    blob_hash: BlobHash,
    pinned_by: Vec<IdentityId>,     // кто pin'ит — может быть несколько
    providers: Vec<ProviderEntry>,  // кто реально хранит сейчас
    paid_until: u64,
}

struct ProviderEntry {
    node_id: NodeId,
    region: GeoZone,
    provider_kind: ProviderKind,    // LocalRelayFree | OrgPaid | ExternalPRO | …
    stored_at: u64,
    verified_until: u64,            // истекает при отсутствии PoS-confirm
    signature: Vec<u8>,
}
  • Когда pinned_by пуст и нет других reasons держать → eligible для GC.
  • actual_providers = providers.iter().filter(|p| now < p.verified_until).count().
  • При недостаче providers'ов для pin'нутого blob'а — запускается repair через anti-entropy (§11d).

12. Жизненный цикл cert'a и таймлайн при неоплате

12.1 Этапы

Период от истечения certРежимЧто нода делаетКто платит за ресурс
Day 0 → 7warningfull service, daily reminderвладелец (текущая подписка)
Day 7 → 14read-only freezereads OK, writes reject, replication-in OKоператор (org / byo)
Day 14 → 21cold archivereads медленные, paid restore offerоператор
Day 21 → 28tombstonereads = 410 Gone, restore возможеноператор
Day 28+hard deleteфизическое удаление

Reactivation: в любой момент до day 28 — достаточно возобновить обычную оплату.

12.2 Кто платит за extra-период

  • org × * → kontinuum.org поглощает.
  • byo:* × * → пользователь продолжает оплачивать VPS своему провайдеру (или сам держит home server); org даёт только cert + lifecycle.

12.3 Распространение в сети

  • Day 7: Tier 0 публикует CertRevocation в global DHT.
  • Peer'ы видят за 1–2 минуты, помечают ноду как read-only.
  • Inter-node операции ReplicaPush / DhtPut к этой ноде отвергаются.
  • DhtGet / ReplicaPull продолжают работать до этапа tombstone.

12.4 Cross-replication safety net

Контент владельца, размещённый в Shared Spaces, переживает full timeline, потому что копии лежат на Tier 1/2 нодах участников. UX-сообщение: «после tombstone ваши shared-space данные останутся доступными у друзей; personal данные исчезнут».


15. Поверхности управления

15.1 Org-side: используем готовые инструменты

Никакого custom Vue3 frontend'а. Стек:

  • Prometheus + Grafana — metrics dashboards: per-node health, DHT lookup latency, replication factor distribution, mailbox queue depths, challenge pass/fail rates, geo-zone distribution.
  • Directus — headless admin panel поверх SQL ноды (CRUD по identity, cert, quota, partner-info, billing-events). Заменяет «admin UI» для day-to-day ops.
  • Operator chat bot — platform-agnostic интерфейс для quick ops (drain mode, force-rebalance, kick offender, ad-hoc queries). Реализуется через operator_bot::BotBackend trait в admin crate; конкретный backend (Kontinuum native / Telegram / Matrix / Signal / Discord) подключается на этапе deployment.
  • REST API (kontinuum-node-admin crate) — для billing webhooks, Tier 0 cert issuance, automation.

16. Модель угроз

УгрозаМитигация
Sybil в global DHTTier 0 anchor + Tier 1 cert-based admission; Tier 2 PoS-challenges; anti-Eclipse: peer-selection обязан включать ≥1 Tier 0/1 ноду
Eclipse конкретной identityidentity-stub в global DHT помещается у k=20 широко рассеянных нод; lookups через ≥3 disjoint paths
MITM identity lookupВсе DHT-записи подписаны owner; client верифицирует подпись
Node compromiseE2E-шифрование данных at rest и in transit; нода ничего не расшифровывает
Tier 0 key compromisev0.1: 1-of-1 + offline backup для emergency recovery. v1.0: 3-of-5 multi-sig для cert issuance / CRL update; 2-of-3 для routine config. Ключи geographically distributed (US, EU, AP)
byo-нода malicious tenant abuseWhitelist by identity_id; per-tenant квоты; revoke в любой момент через PRO admin UI
byo-нода malicious ownerTenant trust'ит owner — это family/team use case; E2E защищает от чтения; tenant может в любой момент мигрировать на другую инфру (Personal Space portable)
Censorship / takedownE2E + cross-provider / cross-region replication; Tier 3-style relay в дружественных регионах
DDoS на нодуТехнические rate limits (token bucket); rejects при перегрузке; partner-level CDN опционально
Cert revocation raceCRL distribution через gossip; nodes ttl-кешируют cert validity максимум 60 секунд
Vault backup leakBackup encrypted with master_key (Argon2id from BIP39); нода видит только ciphertext
Metadata-leak через redirect targetDefault presigned URLs (требуют app-refresh); opt-in public-readable с UX-warning; obscure bucket naming через blake3(identity_id + nonce); disable LIST permission; minimal HEAD responses
Tenant data exposure через host-adminTenant E2E-encrypts с собственным space_key, который admin-владелец host's ноды не имеет; UX-warning при join family-mode (см. §7.3); рекомендация купить собственную relay-node для критичных данных

16.1 DR / chaos planning

Disaster Recovery plan для всей сети при потере целого geo-zone / провайдера.

Recovery primitives (что у нас есть в архитектуре):

PrimitiveГде определено
Cross-region replication§9.2 — RF копий в разных geo-zones
Friend-replication safety net§9.3 — копии у friend's нод
DHT k=20 by xor-distance§5.1.1 — auto-distributed geographically
Tier 0 anchors в разных регионах§3.1 — recommended US, EU, AP
External direct URL fallback§13.6 — bypass dead byo-нод
Friend-replica takeover§20.6 (round 3) — primary serving при offline node

Тестирование:

ПодходКогдаЧто даёт
Game days (manual exercise)Раз в кварталКоманда тренируется coordinated failover; playbook updates
Synthetic chaos в stagingContinuous (low frequency)Verify automated recovery без impact production
Hard takedown testsРаз в полгода, scheduledКоординированный «turn off all EU», measure MTTR
Continuous chaos в prod (Netflix-style)После v1.0 — daily injectionCatch real production issues; требует mature observability

SLO метрики:

МетрикаTarget
MTTR для global DHT lookups при single-zone failure< 60 sec
Data loss rate для billed content (durability)0%
User-visible downtime при failure одного провайдера< 5 min
Full provider migration time (e.g., Hetzner→OVH)< 24h

Playbook для типичных incidents:

  • Один Tier 0 anchor offline → остальные продолжают, при multi-sig 3-of-5 ничего не блокирует (см. A1).
  • Один geo-zone полностью offline → friend-replication + cross-region replicas обслуживают reads; writes failover в healthy zones.
  • Один провайдер полностью offline (e.g., Hetzner outage) → automated detection через NodeStatus (§11h); user notification; manual emergency migration инструкции через admin.
  • Tier 0 root key compromised → emergency revocation через offline backup ключ; coordinated network-wide rotation Tier 0 pubkey list в новой client version.

Rollout plan для v1.0:

  • Game days quarterly с момента launch.
  • Synthetic chaos в staging — после первых 100 nodes.
  • Continuous chaos в prod — после v1.0 stable run (≥6 месяцев).