101 lines
10 KiB
Markdown
101 lines
10 KiB
Markdown
# wireguard-scripts
|
||
|
||
## M1 runtime foundation
|
||
|
||
The current entry point provides dependency-free `help` and `version` commands. The
|
||
planned operational commands are recognized but remain unavailable until later
|
||
milestones.
|
||
|
||
Runtime locations default to the project directory and can be redirected for an
|
||
isolated run with absolute paths using these environment variables:
|
||
|
||
`WG_MANAGER_CONFIG`, `WG_MANAGER_BACKUP_DIR`, `WG_MANAGER_LOG_DIR`,
|
||
`WG_MANAGER_METADATA_DIR`, `WG_MANAGER_ARCHIVE_DIR`, and `WG_MANAGER_LOCK_FILE`.
|
||
|
||
`WG_MANAGER_GUM` selects an executable `gum` explicitly; otherwise the bundled
|
||
`bin/gum` and then `PATH` are checked in that order. Configuration is parsed as
|
||
restricted `KEY=VALUE` data and is never executed as shell code. Blank lines and
|
||
full-line `#` comments are ignored; spaces around the key, `=`, and value are
|
||
trimmed. Values are either one unquoted token or a double-quoted value without
|
||
escapes, and only documented keys are accepted.
|
||
|
||
For deterministic read-only tests, `WG_MANAGER_NOW` may override the current
|
||
epoch when set to decimal seconds; invalid values are rejected.
|
||
|
||
M2 adds read-only `status` and `list`. They parse the configured WireGuard file
|
||
and, when available, `wg show <interface> dump`; a stopped or unavailable
|
||
runtime is reported as unavailable and disk-only peers remain visible. `list`
|
||
uses stable tab-separated output with English machine fields `state` and
|
||
`origin` (`managed`, `legacy`, or `unmanaged`) and never prints private or
|
||
preshared keys.
|
||
|
||
The explicit peer comment marker is `# wg-manager-client: NAME`; it is only a
|
||
display candidate. A peer is considered managed only when its exact public key
|
||
and configured addresses match a valid metadata record with `MANAGED=1`.
|
||
|
||
## M3 transaction foundation
|
||
|
||
The internal `run_transaction OPERATION TARGET BUILDER [METADATA_FILE...]`
|
||
primitive acquires `WG_MANAGER_LOCK_FILE`, then
|
||
reloads and validates the live configuration before calling its builder. It
|
||
creates a restrictive, timestamped backup, validates a same-filesystem staged
|
||
configuration with `wg-quick strip`, replaces the live file atomically, applies
|
||
it with `wg syncconf`, and verifies the active peer set. Apply or verification
|
||
failures restore both disk and runtime; a failed restoration is reported as a
|
||
critical rollback error. No M3 mutation command is exposed yet.
|
||
|
||
M3 tests use only isolated overrides and deny-by-default command mocks; they do
|
||
not inspect or modify host WireGuard state.
|
||
|
||
## M4 client creation
|
||
|
||
`add NAME` creates a client transactionally. The optional forms are
|
||
`--mode full-tunnel|split-tunnel` and `--endpoint HOST`; unknown or extra
|
||
arguments are rejected. Names are restricted to ASCII letters, digits, `.`,
|
||
`_`, and `-` (without a leading `-`). Root is required for production use;
|
||
tests enable only an isolated `WG_MANAGER_TEST_MODE` under `TEST_ROOT`.
|
||
|
||
Private/public/PSK files, client configuration, and metadata use restrictive
|
||
permissions and are removed if the server transaction or rollback fails.
|
||
Generated key material is supplied to `wg` through stdin or stdout and is not
|
||
placed in command arguments or diagnostic output.
|
||
|
||
## M5 inspection and export
|
||
|
||
`show NAME` displays only non-secret peer details and a config path after
|
||
identity, ownership, mode, and path validation. `config NAME` prints only that
|
||
validated path. Full client content requires the explicit noninteractive
|
||
`config NAME --show` form; it never reads separate `.key` or `.psk` files.
|
||
|
||
`qr NAME` feeds the validated config to `qrencode -t ansiutf8` through stdin.
|
||
If the optional `qrencode` dependency is unavailable, it prints the safe config
|
||
path and returns status `69`; QR failures return the operation status. Routine
|
||
show/export/path/error output is secret-free.
|
||
|
||
The inspection commands do not require `gum` or `qrencode` for `show` and
|
||
`config`. `qrencode` is the only optional QR dependency; when it is absent,
|
||
`qr NAME` writes the validated configuration path to stdout and an actionable
|
||
warning to stderr, then returns status `69`. A nonzero `qrencode` result
|
||
returns status `70` without printing configuration content in the diagnostic.
|
||
|
||
Common command statuses are `64` for usage errors, `65` for invalid or unsafe
|
||
client identity/path data, `69` for a missing optional dependency, and `70`
|
||
for an operational read/export/QR failure. `config NAME --show` is the only
|
||
inspection form that writes the complete client configuration to stdout;
|
||
ordinary `show`, `config`, and `qr` output remains secret-safe.
|
||
|
||
## M6 удаление клиента
|
||
|
||
`remove NAME [--yes]` удаляет только подтверждённый managed-peer после повторной проверки точного публичного ключа, адресов и блока под lock. В интерактивном терминале без `--yes` показываются имя, адреса и только последние 8 символов публичного ключа; ответ, отличный от `y`, отменяет операцию без изменений. В неинтерактивном режиме `--yes` обязателен.
|
||
|
||
Изменение серверной конфигурации выполняется внутри транзакции: сначала конфигурация заменяется и проверяется в WireGuard, а затем финализатор архивирует связанные `.conf`, `.meta`, `.key`, `.pub` и `.psk` (если существуют) в уникальный каталог `ARCHIVE_DIR` с режимами `0700`/`0600`. Ошибка архивирования после применения приводит к откату и оставляет исходные файлы доступными для восстановления; архивы не удаляются автоматически и служат восстановительным материалом. Журнал содержит operation, target, UTC timestamp, outcome и короткий суффикс публичного ключа; ключи и содержимое конфигураций в него не записываются.
|
||
|
||
`remove` возвращает `64` для ошибки аргументов, `65` для неподтверждённой или небезопасной identity/path, `69` для отсутствующей обязательной зависимости и `70` для ошибки операции или архивации. Ошибка аудита после успешной мутации явно сообщается и возвращает операционный статус; отмена остаётся успешной без изменения состояния.
|
||
`diagnose [--quiet]` выполняет только read-only проверки конфигурации и прав, наличия интерфейса, `wg` dump, forwarding, адресов/маршрутов IPv4 и IPv6, UDP-порта, firewall, systemd, runtime-vs-disk peer set и журнала. Отдельные записи `config-parse`, `duplicate-keys`, `allowedips-overlap` и `key-permissions` не скрывают независимые причины сбоя. Каждая запись имеет один из статусов `OK`, `WARN`, `FAIL` или `SKIP`; `--quiet` выводит только стабильные строки `id=STATUS`. Обязательны `wg`, `wg-quick` и `ip`; `systemctl`, `journalctl`, `nft`, `iptables` и `ss` являются optional и при отсутствии дают собственный `SKIP`. На хосте без активного systemd проверки systemd и журнала пропускаются. `firewall=OK` означает только видимое ожидаемое NAT-свидетельство, а не полную проверку политики firewall. Ненулевой код (`70`) возвращается при любом `FAIL`, `64` — при неверных аргументах. Команда не изменяет конфигурацию, runtime, маршруты, firewall или sysctl; handshake и журнал имеют ограниченную историческую видимость. Тесты используют только изолированные fixtures/mocks и не доказывают состояние реального сервера.
|
||
|
||
## M8 резервные копии, восстановление и аудит
|
||
|
||
`backup` создаёт ручную резервную копию текущей серверной конфигурации под lock; `backups` показывает только проверенные прямые дочерние каталоги, в порядке от новых к старым. Повреждённые или неполные записи не исполняются и не читаются как shell-код. `restore BACKUP [--yes]` восстанавливает только серверную конфигурацию: перед заменой текущая версия также резервируется, а ошибки применения проверяют и откатывают disk/runtime. Восстановление другой WireGuard-интерфейсной конфигурации отклоняется. Без `--yes` требуется подтверждение в терминале; в неинтерактивном режиме команда возвращает ошибку использования. Клиентские metadata/key-файлы восстановлением не изменяются.
|
||
|
||
`log [LIMIT]` выводит только корректные структурированные audit-события в newest-first порядке; `LIMIT` находится в диапазоне 1..1000. При отсутствии журнала выводится безопасное сообщение. Записи содержат UTC timestamp, actor UID, operation, target, outcome и короткую категорию ошибки; секреты, команды и полные конфигурации не записываются. Ошибки аудита после успешной мутации сообщаются как частичный операционный результат. Основные коды: `64` — аргументы, `65` — небезопасная/невалидная backup identity, `70` — ошибка операции; критический неудачный rollback сохраняет отдельный rollback status.
|