Kontinuum Node — Configuration
TOML config schema для
kontinuum-node-serverиkontinuum-node-admin, env-vars override, secrets management. P0 prerequisite — определяет format перед началом кодингаconfig.rs.
Audience: node developers · ops · operator onboarding.
Связанные документы:
db-schemas.md— config указывает paths для DBarchitecture.md— tier model, capabilities (формируют section'ы конфига)operations.md— admin config интегрируется с billing, Tier 0 RPC
Обзор
Два разных config-файла per deployment:
| Process | Config файл | Default location |
|---|---|---|
kontinuum-node-server | node.toml | /etc/kontinuum-node/node.toml (prod) или ./config/node.toml (dev) |
kontinuum-node-admin | admin.toml | /etc/kontinuum-node-admin/admin.toml |
Загрузка config'a:
- Path указан через CLI flag (
--config /path/to/node.toml) — primary. - Иначе — default path для environment.
- Env vars override любое поле из TOML (см. §Env vars).
- Validation — fail-fast при startup; ошибки идут в stderr + лог.
TOML chosen because:
- Human-readable, легче чем YAML для ops без YAML-traps (indentation, type ambiguity).
- Native Rust support через
configcrate (уже в Cargo.toml какconfig = "0.14"). - Comments allowed — important для operator handbook.
node.toml schema
Полный пример
# Kontinuum Node — node.toml
# Reference: docs/node/configuration.md
[identity]
# Path to Ed25519 signing key (encrypted with master_key).
# Generated at first run, chmod 600.
key_path = "/var/lib/kontinuum-node/keys/node.key"
# Path to Tier 0-signed cert (None для Tier 2 pure-volunteer).
cert_path = "/var/lib/kontinuum-node/keys/node.cert"
# Path для BIP39 recovery phrase (write-only при onboarding, потом file removed).
# Stored encrypted с pin.
# recovery_phrase_path = "/var/lib/kontinuum-node/keys/recovery.enc"
[network]
# libp2p listen multiaddrs.
listen_addrs = [
"/ip4/0.0.0.0/tcp/4001",
"/ip4/0.0.0.0/udp/4001/quic-v1",
"/ip6/::/tcp/4001",
]
# Optional advertised external addrs (если за NAT, прописать вручную).
external_addrs = []
# Tier 0 bootstrap peers — hardcoded в коде (см. bootstrap.md).
# Дополнительные bootstrap peers для test/dev environments — указать здесь.
extra_bootstrap_peers = []
# Connection limits.
max_connections = 1000
connection_idle_timeout_secs = 300
# Noise + Yamux config tuning — defaults usually fine.
# yamux_window_size = 16777216 # 16 MB
# noise_handshake_timeout_secs = 30
[storage]
# Base data directory. DB files, rustfs blob storage, transient cache.
data_dir = "/var/lib/kontinuum-node/data"
# DB file paths (relative to data_dir или absolute).
db_path = "node.db"
# Disk allocation (см. §7.2 — relay-node как coordination + free S3).
# total = system_reserved + dht_storage + cache + free_s3 (computed)
max_total_gb = 20
# Quotas для каждого components (хосткa нагрузки).
dht_storage_gb = 3
cache_storage_gb = 3
system_reserved_gb = 2
# free_s3_gb = max_total_gb - sum(above) = 12
[storage.rustfs]
# Embedded rustfs configuration.
# Backend: filesystem | memory (for tests).
backend = "filesystem"
backend_path = "rustfs/" # relative to data_dir
listen_addr = "127.0.0.1:9000"
# Authentication is via Ed25519 shim, not SigV4. Internal port only.
[capabilities]
# Capabilities, declared by node в `node:{node_id}` записи.
# `dht_routing` всегда mandatory — не нужно перечислять явно.
# Допустимые значения: relay, storage, mailbox, s3_gateway, anti_entropy, rendezvous
enabled = ["relay", "storage", "mailbox", "s3_gateway", "anti_entropy"]
# rendezvous default OFF для Tier 2 byo (см. §6.6).
[tier]
# Tier and tenancy mode.
tier = 1 # 0 | 1 | 2
tenancy = "single" # "multi" | "single"
operator = "org" # "org" | "byo:vps" | "byo:home"
# Для single-tenant — identity_id владельца (hex-encoded blake3 of pubkey).
# Для multi-tenant — оставьте пустым.
served_identity = "a3f9..."
[geo]
# Geographic zone — где physically running this node.
host_geo_zone = "eu-west"
# Default geo для own buckets (если не override'ится per-bucket).
bucket_default_geo_zone = "eu-west"
[observability]
# Prometheus metrics endpoint.
prometheus_listen = "127.0.0.1:9100"
# Logging.
log_level = "info" # trace | debug | info | warn | error
log_format = "json" # "json" | "text"
# OpenTelemetry tracing (optional).
# tracing_endpoint = "http://otel-collector:4317"
[tenants]
# Family-mode whitelist (для byo:* × multi). Empty для single-tenant.
# Каждый tenant с per-tenant квотами.
# Подписи квот сохраняются в DB (tenant_quotas), это просто onboarding source.
whitelist = []
# [[tenants.whitelist]]
# identity_id = "b7c2..."
# max_storage_bytes = 5000000000 # 5 GB
# max_mailbox_bytes = 100000000 # 100 MB
# max_mailbox_messages = 10000
[reencryption]
# Background re-encryption job parameters (§5.2.3 forward secrecy).
batch_size = 50 # blob/batch processed in one cycle
batch_interval_secs = 60
parallelism = 4
[anti_entropy]
# Merkle-tree gossip parameters (§11d).
gossip_interval_secs = 300 # 5 min
partition_count = 256
max_descend_depth = 16
[challenge]
# PoS challenge cadence (для Tier 2 verification).
issue_interval_secs = 3600 # 1h
sample_size_per_cycle = 10
score_threshold_eviction = -100Required vs optional fields
Required (validation fails при отсутствии):
identity.key_pathnetwork.listen_addrs(минимум 1)storage.data_dir,storage.db_pathtier.tier,tier.tenancy,tier.operatorgeo.host_geo_zone
Optional с defaults:
network.max_connections→ 1000network.connection_idle_timeout_secs→ 300storage.max_total_gb→ 20storage.dht_storage_gb→ 3storage.cache_storage_gb→ 3capabilities.enabled→["relay", "storage", "mailbox"]observability.log_level→ "info"observability.log_format→ "json"reencryption.batch_size→ 50anti_entropy.gossip_interval_secs→ 300challenge.issue_interval_secs→ 3600
Cross-field validation:
tenancy = "single"→served_identityобязателен.tenancy = "multi"→served_identityдолжен быть пустым.operator = "org"→tier∈ {0, 1}.operator = "byo:vps" | "byo:home"→tier = 2.tier = 0→ cert_path может быть пустым (Tier 0 self-signed).tier ∈ {1, 2}→ cert_path обязателен.- Sum(
dht_storage_gb+cache_storage_gb+system_reserved_gb) <max_total_gb.
admin.toml schema
# Kontinuum Node Admin — admin.toml
# Reference: docs/node/configuration.md
[admin]
# Admin process listens на REST API для org operators.
rest_listen = "127.0.0.1:8080"
db_path = "/var/lib/kontinuum-node-admin/data/admin.db"
[operator_bot]
# Platform-agnostic operator chat bot для quick ops. Implemented via
# operator_bot::BotBackend trait в admin crate.
enabled = true
# Backend identifier — "kontinuum" | "telegram" | "matrix" | "signal"
# | "discord" | "noop". At v0.1 only "noop" doesn't need credentials;
# concrete backends pull their own SDK and read credentials from
# `credentials_file`.
backend = "noop"
credentials_file = "/etc/kontinuum-node-admin/secrets/operator_bot_credentials"
# Identifier whitelist (backend-specific format — chat_id, JID, phone, etc.).
allowed_operators = []
[billing_integration]
# Kontinuum Billing webhook endpoint (inbound).
webhook_listen = "0.0.0.0:9090"
webhook_secret_file = "/etc/kontinuum-node-admin/secrets/billing_webhook_secret"
# Kontinuum Billing API (outbound, для cert issuance triggers).
billing_api_url = "https://billing.kontinuum.local/api/v1"
billing_api_key_file = "/etc/kontinuum-node-admin/secrets/billing_api_key"
[tier0]
# Tier 0 anchor endpoint (admin process сам Tier 0 nor talks to Tier 0).
# Для cert issuance flow — admin отправляет signing request на Tier 0 multi-sig group.
tier0_endpoint = "https://tier0.kontinuum.local/api/v1"
tier0_client_key_file = "/etc/kontinuum-node-admin/secrets/tier0_client.key"
[observability]
prometheus_listen = "127.0.0.1:9101"
log_level = "info"
log_format = "json"
[directus]
# Directus headless CMS, integrated для admin UI.
# Admin process exposes DB read-only через PostgreSQL bridge.
# Directus сам управляется отдельно (см. deploy/directus/).
directus_db_user = "directus_read"
directus_db_password_file = "/etc/kontinuum-node-admin/secrets/directus_db_pw"Env vars override
Все TOML fields могут быть override'ны через env vars. Convention: KONTINUUM_NODE_<SECTION>_<FIELD>.
| TOML path | Env var |
|---|---|
identity.key_path | KONTINUUM_NODE_IDENTITY_KEY_PATH |
network.listen_addrs[0] | KONTINUUM_NODE_NETWORK_LISTEN_ADDRS_0 |
storage.data_dir | KONTINUUM_NODE_STORAGE_DATA_DIR |
tier.tier | KONTINUUM_NODE_TIER_TIER |
observability.log_level | KONTINUUM_NODE_OBSERVABILITY_LOG_LEVEL |
tenants.whitelist | KONTINUUM_NODE_TENANTS_WHITELIST_JSON (JSON-encoded array) |
Для admin process — prefix KONTINUUM_NODE_ADMIN_.
Precedence: env vars > TOML > defaults.
Useful overrides:
- Tests:
KONTINUUM_NODE_STORAGE_DATA_DIR=/tmp/test-node-$$ - Container: bake env vars в Dockerfile или Helm values.
- Secrets: НЕ через env vars (utilites like
ps,/proc/<pid>/environmay leak); только через file-paths.
Secrets management
Принципы
- Никогда не хранить secrets в config файле напрямую (TOML текстовый).
- Всегда через file paths — config указывает где, файл сам chmod 600.
- Master_key — derived at startup из BIP39, держится в-memory только.
- Backup-копии secrets — encrypted (LUKS / GPG), хранятся offline.
Files convention
/var/lib/kontinuum-node/keys/
├── node.key # Ed25519 signing key (encrypted with master_key) — chmod 600
├── node.cert # Tier 0-signed cert binary — chmod 644
└── recovery.enc # encrypted BIP39 phrase (optional, removed после bootstrap) — chmod 600/etc/kontinuum-node-admin/secrets/
├── operator_bot_credentials # operator chat bot credentials (backend-specific format) — chmod 600
├── billing_webhook_secret # HMAC secret для webhook verify — chmod 600
├── billing_api_key # API key для outbound calls — chmod 600
├── tier0_client.key # client cert для Tier 0 RPC — chmod 600
└── directus_db_pw # postgres password для Directus — chmod 600Owner / group:
- Server process runs как
kontinuum-nodeuser, owner of/var/lib/kontinuum-node/. - Admin process runs как
kontinuum-node-adminuser, owner of/etc/kontinuum-node-admin/secrets/. - Никаких world-readable secrets.
Master key derivation
master_key = Argon2id(
password = BIP39_phrase,
salt = "kontinuum-node-master-v1",
memory = 65536 KB,
iterations = 3,
parallelism = 4,
output_len = 32 bytes,
)Same algorithm как kontinuum-app::vault::recovery. Master key stays в-memory, NEVER persisted on disk plaintext. После derivation BIP39 phrase wiped из process memory.
Если перезапуск ноды — admin приходит, вводит BIP39 phrase через interactive prompt (или PIN unlock через pin_encryption::ValidatedPin, если ранее настроен PIN — analogous to kontinuum-app::vault::pin_encryption).
Per-environment configs
Convention для dev / staging / prod:
config/
├── node.toml.dev # local development
├── node.toml.staging # staging environment
└── node.toml.prod # productionStartup flag: --config config/node.toml.prod.
Что отличается между environments:
| Field | dev | staging | prod |
|---|---|---|---|
network.listen_addrs | 127.0.0.1:4001 | 0.0.0.0:4001 | 0.0.0.0:4001 + external_addrs |
network.extra_bootstrap_peers | tests's mock Tier 0 | staging Tier 0 cluster | empty (uses hardcoded prod Tier 0) |
storage.data_dir | ./data/ | /var/lib/kontinuum-node/data/ | /var/lib/kontinuum-node/data/ |
storage.max_total_gb | 1 | 5 | 20 |
observability.log_level | debug | info | info |
observability.log_format | text | json | json |
tier.tier | 1 (mocked cert) | 1 | 1 (real cert from prod Tier 0) |
Containerization (production)
Standard Docker image:
FROM kontinuum-node:v1.0
# Bake default config — env vars override at runtime.
COPY node.toml.prod /etc/kontinuum-node/node.toml
ENV KONTINUUM_NODE_STORAGE_DATA_DIR=/data
VOLUME ["/data", "/var/lib/kontinuum-node/keys"]
EXPOSE 4001 9100
ENTRYPOINT ["/usr/local/bin/kontinuum-node-server"]
CMD ["--config", "/etc/kontinuum-node/node.toml"]Kubernetes: ConfigMap для node.toml, Secret для keys, PVC для data_dir.
Validation
At startup
async fn load_and_validate(path: &Path) -> Result<NodeConfig> {
let raw = std::fs::read_to_string(path)?;
let mut cfg: NodeConfig = toml::from_str(&raw)?;
// Override from env vars.
cfg.apply_env_overrides()?;
// Required-field check.
cfg.validate_required()?;
// Cross-field constraints.
cfg.validate_consistency()?;
// File-path existence (key, cert).
cfg.validate_paths()?;
// Permission check (chmod 600 для secrets).
cfg.validate_permissions()?;
Ok(cfg)
}Error messages
User-friendly с clear hint к fix:
ERROR: tier.served_identity is required when tenancy="single"
in /etc/kontinuum-node/node.toml line 24
Hint: add `served_identity = "<hex blake3 of owner pubkey>"` или change tenancy to "multi".ERROR: identity.key_path "/var/lib/kontinuum-node/keys/node.key" не существует
и has wrong permissions
Hint: первый запуск? Generate identity через:
kontinuum-node-server bootstrap --output /var/lib/kontinuum-node/keys/node.keyHot reload
Reloadable fields
При SIGHUP config перечитывается; следующие поля применяются без рестарта:
observability.log_levelobservability.log_formatnetwork.max_connectionsnetwork.connection_idle_timeout_secsreencryption.batch_size/batch_interval_secs/parallelismanti_entropy.gossip_interval_secschallenge.issue_interval_secstenants.whitelist(если valid signatures)
Non-reloadable (требуют restart)
identity.*— signing key / cert changesnetwork.listen_addrs— bind addr changesstorage.*— DB path / quotas (избежать data loss)tier.*— tier transitions through cert lifecycle, не config-levelgeo.*— node geo identity, fixedcapabilities.enabled— restart safer для clean DHT membership change
При попытке reload non-reloadable field — log warning, ignore, продолжить со старым value.
CLI flags
kontinuum-node-server
kontinuum-node-server [OPTIONS]
OPTIONS:
--config <PATH> Path to node.toml (default: /etc/kontinuum-node/node.toml)
--log-level <LEVEL> Override log level (trace/debug/info/warn/error)
--data-dir <PATH> Override storage.data_dir
--dry-run Validate config and exit без start'a network
--version Print version and exit
SUBCOMMANDS:
bootstrap Generate identity, vault, BIP39 phrase (first run)
cert request Request cert from Tier 0 (manual flow for testing)
dump-state Print DB state to stdout (debugging)kontinuum-node-admin
kontinuum-node-admin [OPTIONS]
OPTIONS:
--config <PATH> Path to admin.toml
--log-level <LEVEL>
--version
SUBCOMMANDS:
server Start REST API + operator chat bot + billing webhook listener
cert issue <node_id> Issue cert (calls Tier 0 multi-sig flow)
cert revoke <node_id> Add to CRL
node drain <node_id> Set drain mode
audit dump Export admin_audit_logImplementation checklist
- [ ] Добавить
config = "0.14",toml = "0.8",dotenv = "0.15"(для test env vars) вCargo.toml. - [ ] Implement
NodeConfigstruct вconfig.rsсserde::Deserialize. - [ ] Implement env-var override layer (
config::Environment::with_prefix("KONTINUUM_NODE")). - [ ] Implement validation functions (required, consistency, paths, permissions).
- [ ] Implement CLI args parsing через
clap. - [ ] Implement
SIGHUPhandler для hot reload. - [ ] Sample config files в
config/node.toml.{dev,staging,prod}(включая в repo как reference). - [ ] Tests: load valid config, reject invalid, env override works, permissions check fires.
- [ ] Documentation in
--helptext (rustdoc + clap docs).
Open implementation questions
- Hot-reload SIGHUP vs config-watcher (inotify) — SIGHUP проще, но inotify более responsive. Решить при имплементации.
config::Environment::with_prefixvs custom env-merge — config crate handles большинство случаев, но JSON-encoded arrays через env требуют custom logic.- Schema validation tooling — JSON Schema + validator или Rust-only? JSON Schema удобнее для external tools (Directus form generation, etc.).
- Secrets management — Vault / age / pass / plain files — для v1.0 plain files chmod 600 OK; для multi-machine production может потребоваться HashiCorp Vault интеграция.
- Encrypted backup format —
rage(age in Rust) vs GPG vs custom?rageminimal, modern crypto.