4.9 KiB
4.9 KiB
Криптографический аудит харнеса (t-260930083716)
Запрос Alex (m-516173240): у харнеса свой приватный ключ; каждое событие стора и каждая команда подписаны. Цели: полная аудируемость, доказуемое авторство («сделал харнес»), защита стора и командной шины от инъекций.
Схема
- Алгоритм: ed25519 (библиотека
cryptography). - Ключи: прив.
/root/simbiot-harness/.audit/ed25519.key(0600, создан атомарно tmp+rename), публ. рядомed25519.pub(0644, отдавай внешним аудиторам).key_id= первые 16 hex sha256 от публ. ключа. - Активные ключи (созданы 2026-10-02):
- pubkey (raw b64):
P8puVpwg9UtKtEnYUKCCGz/NA4zXU1ubgkdurp2V+CY= - key_id:
faf8d19d9aed71fe
- pubkey (raw b64):
Что подписывается
- События стора —
es.append_eventподписывает каждое событие при записи. Плайлоад:aggregate|aggregate_id|event_type|canonical_json(data)| timestamp|version|prev_sig|key_id(\x1f-сшит). В колонки события пишутсяsig, key_id, prev_sig. - Тампер-цепочка:
prev_sigкаждого события = подпись предыдущего — переписать середину стора, не сломав голову цепочки, нельзя. - Команды CLI —
cli.py audit-command '{"op":…}'→ конверт{envelope, payload_b64, signature, key_id}; вход в командную шину верифицируетсяcli.py verify-command(выход 0/2).
Верификация
cli.py verify— полный аудит цепочки (выход 0/2): криптопроверка каждой подписанной строки + link-checkprev_sig. Может выполнять любая внешняя сторона с публичным ключом.- Проекции (
es.run_projections) проверяют хвост-дельту: событие с битой подписью или разрывом цепочки ⇒ RuntimeError — подделка не попадает в read model (проверено тестом). cli.py audit-key— публичный ключ/отпечаток/пути.
Граница доверия: genesis и legacy
- Все события до внедрения подписи (2026-10-02, 465 255 шт.) помечены
ретро-маркером
sig='genesis:<id>'(водяной знакprojection_meta. sig_genesis_upto— раз и навсегда). Это честная граница: до неё авторство не доказывалось криптоключом. - Подписанная строка после границы, чей
prev_sigуказывает на дого- генезисное состояние, не бракуется по link-check (граница сбрасывает проверку сцепки), но её payload-подпись строго проверяется — контент послегенезисной строки тамперить нельзя. - Неподписанные послегенезисные строки (старый код демонов до их рестарта)
=
legacy: аудит их считает, ошибкой является только тампер подписанной строки. После рестарта сервисов (просьба к Alex в дайджесте дня) всё новое гарантированно подписано.
Инвариант защиты
| Атака | Чем ловится |
|---|---|
| Правка data/timestamp события | подпись payload (verify) |
| Правка middle-строки всего стора | подпись + цепочка (full audit) |
| Вставка фейкового события | нет валидной подписи → legacy-статус, но не «валидный харнес»; в хвосте проекций — RuntimeError |
| Подмена команды | конверт-подпись (verify-command) |
| Кража подписи | плайлоад привязан к содержимому; ключ 0600 |
Файлы
harness/audit.py— ключи, каноника, sign/verify, командные конвертыharness/es.py— миграция (sig-колонки/genesis), подпись вappend_event, хвост-верификация вrun_projectionscli.py—verify,audit-command,verify-command,audit-key- Тест:
tests/test_audit.py(17 проверок, hermetic: тампер/genesis/ legacy/конверты/CLI)