9d2d2bc0c2
Добавлен package-режим в tools/build.sh: --package, --dist-dir, --version. Реализована сборка Debian-пакета, metadata/control, postinst/postrm и SHA256SUMS. Установочные пути унифицированы под /usr/sbin и /lib/systemd/system для production-модели.
132 lines
9.0 KiB
Markdown
132 lines
9.0 KiB
Markdown
# Acceptance checklist перед production-выкладкой
|
||
|
||
## A. Базовая установка
|
||
|
||
- [ ] Хост — Debian 13 amd64.
|
||
- [ ] Сервер выделенный, без соседних сервисов.
|
||
- [ ] AmneziaWG/AWG 2.0 установлена официальным способом.
|
||
- [ ] Контейнер `amnezia-awg2` или `amnezia-awg` запущен.
|
||
- [ ] `docker ps` видит контейнер.
|
||
- [ ] Можно получить PID контейнера.
|
||
- [ ] `/proc/<pid>/ns/net` существует.
|
||
- [ ] На хосте доступны `ip`, `tc`, `wg`, `nsenter`, `modprobe`.
|
||
- [ ] `awg2-harness validate-config` проходит без ошибок.
|
||
|
||
## B. Peer discovery
|
||
|
||
- [ ] `awg2-harness status` показывает найденный контейнер.
|
||
- [ ] `awg2-harness status` показывает PID/netns контейнера.
|
||
- [ ] `awg2-harness status` показывает найденный интерфейс.
|
||
- [ ] Количество peers совпадает с `wg show all allowed-ips`.
|
||
- [ ] Offline peers с allowed IP тоже попадают в список shaping.
|
||
- [ ] IP вне `amnezia.peer_ipv4_cidr` не попадают в traffic shaping.
|
||
|
||
## C. Traffic topology parity with old bash
|
||
|
||
- [ ] `awg2-harness apply-limits` успешно завершается.
|
||
- [ ] На AWG/WG-интерфейсе есть root qdisc `1: htb`.
|
||
- [ ] На AWG/WG-интерфейсе есть root class `1:1` с `traffic.root_rate`.
|
||
- [ ] Для каждого peer есть class `1:<id>` с `traffic.peer_limit`.
|
||
- [ ] Для каждого peer есть `fq_codel` под `1:<id>`.
|
||
- [ ] Для каждого peer есть egress filter `dst peer_ip -> 1:<id>`.
|
||
- [ ] Есть ingress qdisc `ffff:` на AWG/WG-интерфейсе.
|
||
- [ ] Есть ingress redirect через `mirred ... redirect dev ifb0`.
|
||
- [ ] `ifb0` существует и находится в UP state.
|
||
- [ ] На `ifb0` есть root qdisc `2: htb`.
|
||
- [ ] На `ifb0` есть root class `2:1` с `traffic.root_rate`.
|
||
- [ ] Для каждого peer есть class `2:<id>` с `traffic.peer_limit`.
|
||
- [ ] Для каждого peer есть `fq_codel` под `2:<id>`.
|
||
- [ ] Для каждого peer есть ingress filter `src peer_ip -> 2:<id>`.
|
||
- [ ] Class ids начинаются с `traffic.class_start_id`, default `10`.
|
||
- [ ] Peer IP → class id mapping сохраняет bash parity: IP сортируются лексикографически как строки, не numeric IPv4.
|
||
|
||
## D. Idempotency and drift recovery
|
||
|
||
- [ ] Повторный `apply-limits` не создаёт дубли.
|
||
- [ ] Повторный `apply-limits` не меняет healthy state без причины.
|
||
- [ ] Если удалить root qdisc на AWG/WG-интерфейсе, daemon восстанавливает topology.
|
||
- [ ] Если удалить ingress qdisc, daemon восстанавливает topology.
|
||
- [ ] Если удалить ingress redirect filter (`parent ffff:`), drift детектируется и topology восстанавливается.
|
||
- [ ] Если удалить `ifb0`, daemon восстанавливает topology.
|
||
- [ ] Если сделать `ifb0` DOWN, drift детектируется и topology восстанавливается.
|
||
- [ ] Если удалить один peer filter, daemon восстанавливает topology.
|
||
- [ ] Если изменить `rate/ceil` peer class, drift детектируется и topology восстанавливается.
|
||
- [ ] Если добавить stale peer class/filter, drift детектируется и topology восстанавливается.
|
||
- [ ] После удаления peer устаревшие class/filter исчезают через rebuild.
|
||
- [ ] После добавления peer появляются новые class/filter.
|
||
|
||
## E. Auto-healing lifecycle
|
||
|
||
- [ ] `docker restart amnezia-awg2` → лимиты восстанавливаются автоматически.
|
||
- [ ] `systemctl restart docker` → после возвращения контейнера лимиты восстанавливаются автоматически.
|
||
- [ ] `systemctl restart awg2-harness` → сервис сам находит контейнер и применяет/проверяет лимиты.
|
||
- [ ] Reboot хоста → сервис стартует и восстанавливает лимиты.
|
||
- [ ] Изменение имени интерфейса на допустимое fallback-имя не ломает detector.
|
||
- [ ] Если контейнер временно отсутствует, daemon логирует ожидание и продолжает работу.
|
||
|
||
## F. Status and observability
|
||
|
||
- [ ] `status` показывает desired peer limit из конфига, а не hardcoded 70.
|
||
- [ ] `status` показывает egress state.
|
||
- [ ] `status` показывает ingress/ifb state.
|
||
- [ ] `status` показывает WireGuard clients (online/offline, latest handshake, RX/TX, endpoint).
|
||
- [ ] `status` показывает missing/stale peer rules.
|
||
- [ ] `status` явно показывает partial/drift state.
|
||
- [ ] `status` показывает tc filter counters по peer или `filter statistics: unavailable`.
|
||
- [ ] Логи доступны через `journalctl -u awg2-harness`.
|
||
- [ ] Ошибка отсутствия `tc`/`ip`/`wg` логируется явно.
|
||
- [ ] Последний reconcile result виден в status или journal.
|
||
- [ ] `status` показывает последние события reconcile/firewall из `/run/awg2-harness/events.log`.
|
||
|
||
## G. Reboot scheduler
|
||
|
||
- [ ] Если `reboot.enabled = false`, сервис не планирует reboot.
|
||
- [ ] Если `reboot.enabled = true`, в journal видна запланированная перезагрузка.
|
||
- [ ] Время попадает в окно `window_start_utc`–`window_end_utc`.
|
||
- [ ] Вызов reboot выполняется через `systemctl --no-block reboot`.
|
||
|
||
## H. Swap
|
||
|
||
- [ ] `ensure-swap` создаёт `/swapfile` размером 2048 MB.
|
||
- [ ] Права `/swapfile` — `0600`.
|
||
- [ ] `swapon --show` показывает активный swap.
|
||
- [ ] В `/etc/fstab` нет дублей.
|
||
- [ ] `vm.swappiness = 1` применён.
|
||
- [ ] Повторный `ensure-swap` не пересоздаёт корректный swap.
|
||
- [ ] Несовместимый существующий swap не удаляется молча.
|
||
|
||
## I. Anti-torrent nftables guard
|
||
|
||
- [ ] Если `anti_torrent.enabled = true`, в Amnezia netns есть `table inet awg2_harness`.
|
||
- [ ] Есть chain `forward_antitorrent` с hook `forward` и policy `accept`.
|
||
- [ ] Правило ограничивает `ip saddr <peer_ipv4_cidr>`, default `10.8.1.0/24`.
|
||
- [ ] Лимит считается per source VPN IP через meter/set, а не глобально по всей подсети.
|
||
- [ ] Порог совпадает с `anti_torrent.max_connections_per_peer`, default `100`.
|
||
- [ ] Drop counter виден в `status`.
|
||
- [ ] На first-run без table `awg2-harness apply-firewall` создаёт `table inet awg2_harness`, а не падает.
|
||
- [ ] При превышении порога новые flows дропаются, established flows ниже порога не ломаются.
|
||
- [ ] После restart контейнера nftables rule пересоздаётся в новом netns.
|
||
- [ ] При `anti_torrent.enabled = false` удаляется/отключается только AWG2-owned nftables state; Docker/Amnezia rules не flush-ятся.
|
||
- [ ] `status` показывает `nf_conntrack_count` / `nf_conntrack_max`, если sysctl доступны.
|
||
|
||
## J. Rollback
|
||
|
||
- [ ] Старые bash-файлы сохранены до завершения миграции.
|
||
- [ ] Известно, как остановить `awg2-harness.service`.
|
||
- [ ] Известно, как вернуть `amnezia-tc.service` и `amnezia-tc-watcher.service`.
|
||
- [ ] Rollback проверен на тестовом сервере.
|
||
|
||
## K. Packaging / release
|
||
|
||
- [ ] Package собирается на отдельной Debian 13 amd64 build-machine.
|
||
- [ ] Production host не требует Rust/cargo/source tree.
|
||
- [ ] `./tools/build.sh --package` создаёт `dist/awg2-harness_<version>_amd64.deb`.
|
||
- [ ] `dist/SHA256SUMS` валидирует checksum пакета.
|
||
- [ ] Пакет ставит бинарь в `/usr/sbin/awg2-harness`.
|
||
- [ ] Пакет ставит unit в `/lib/systemd/system/awg2-harness.service`.
|
||
- [ ] Пакет не устанавливает `/etc/awg2-harness/config.toml` автоматически.
|
||
- [ ] Пакет не включает/не стартует сервис автоматически.
|
||
- [ ] `apt install ./awg2-harness_<version>_amd64.deb` проходит на clean Debian 13 Amnezia host.
|
||
- [ ] После ручной установки config `awg2-harness validate-config` проходит.
|
||
- [ ] Сервис стартует только после явного `systemctl enable --now awg2-harness.service`.
|