144 lines
7.6 KiB
Markdown
144 lines
7.6 KiB
Markdown
# wireguard-admin
|
||
|
||
This repository contains the Rust package, startup boundary, validated settings
|
||
loader, client domain model, a byte-preserving WireGuard configuration editor,
|
||
encrypted client vault and read-only import APIs, recoverable saved-file
|
||
persistence, private backups, Commit, and previewed full restore. The library
|
||
also provides read-only WireGuard runtime observation, technical peer comparison,
|
||
bounded systemd restart handling, and explicit restart orchestration. The
|
||
terminal management interface is not implemented, and management startup is not
|
||
connected to these library operations.
|
||
|
||
The package requires Rust 1.97.1 or newer and uses the Rust 2024 edition. From
|
||
the repository root, run:
|
||
|
||
```sh
|
||
cargo run -- --help
|
||
cargo run -- --version
|
||
```
|
||
|
||
`--help` and `--version` work without root. Starting with no arguments requires
|
||
root; until the management interface is implemented, startup exits with an
|
||
error and does not read server configuration or vault files.
|
||
|
||
## Settings
|
||
|
||
Settings use TOML in the fixed file `wireguard-admin.toml` beside the
|
||
executable. Start from [`config/wireguard-admin.example.toml`](config/wireguard-admin.example.toml).
|
||
The required fields are:
|
||
|
||
- `interface_name`: existing WireGuard interface name (1–15 ASCII characters).
|
||
- `server_config_path`: path to the existing server configuration.
|
||
- `client_source_directory`: directory containing existing client files.
|
||
- `server_endpoint`: hostname or IPv4 address followed by `:port`, or IPv6 in
|
||
brackets followed by `:port` (for example, `[2001:db8::2]:51820`).
|
||
- `ipv4_allocation_range` and `ipv6_allocation_range`: CIDR ranges of the
|
||
matching address family.
|
||
- `dns_addresses`: non-empty list of IPv4 and/or IPv6 literal addresses.
|
||
- `systemd_unit`: service unit name ending in `.service`.
|
||
- `restart_timeout_seconds`: positive integer.
|
||
|
||
`data_root` is optional. It defaults to `Backup` beside the executable;
|
||
current internal data and the encrypted vault are under `data`, and archives
|
||
are under `archives`. Relative configured paths, including an explicit
|
||
`data_root`, resolve from the executable directory. Absolute paths remain
|
||
absolute. Settings validation checks syntax and values only; it does not
|
||
require the referenced files, directories, or service to exist and does not
|
||
perform DNS lookups.
|
||
|
||
## Library configuration API
|
||
|
||
The library exposes `wireguard_admin::wireguard::ConfigDocument` for UTF-8
|
||
configuration bytes supplied by the caller. It retains the source and renders
|
||
unmodified input byte-for-byte, including line endings and a missing final
|
||
newline. Peer inspection exposes public identities, parsed `AllowedIPs`, spans,
|
||
and redacted issues; arbitrary directive values are not included in the view.
|
||
The edit methods `add_client`, `delete_client`, `rename_client`, and
|
||
`insert_legacy_metadata` return new in-memory documents. They do not read or
|
||
write files, save changes, or alter the running VPN. See
|
||
[`docs/CONFIG_FORMAT.md`](docs/CONFIG_FORMAT.md) for the managed metadata block
|
||
format.
|
||
|
||
Example:
|
||
|
||
```rust,ignore
|
||
use wireguard_admin::wireguard::ConfigDocument;
|
||
|
||
let document = ConfigDocument::parse(config_bytes)?;
|
||
let updated = document.rename_client(&public_key, "office laptop")?;
|
||
let bytes_to_review = updated.render(); // no persistence or VPN operation
|
||
```
|
||
|
||
Management startup still exits with an explicit “not implemented” error after
|
||
its root check. Runtime and restart library behavior is covered with synthetic
|
||
fixtures and fake adapters; it has not been validated against a real WireGuard
|
||
interface or systemd service. Real WireGuard integration is deferred to the
|
||
isolated Alpine milestone, and real systemd/D-Bus acceptance requires the
|
||
disposable VM milestone.
|
||
|
||
## Saved state, Commit, and backups
|
||
|
||
wireguard_admin::app::Application opens saved files through
|
||
wireguard_admin::persistence::SavedStore, stages client and vault changes,
|
||
creates manual and mandatory operation backups, and previews/confirms a full
|
||
restore. Commit writes saved files only. Restore also changes saved files only;
|
||
neither operation reloads or restarts WireGuard. The server file is kept at its
|
||
trusted configured path, while internal state and the encrypted vault are kept
|
||
under Backup/data by default. Archives are stored under Backup/archives and
|
||
contain fixed logical members, not source client files or prior archives.
|
||
|
||
The persistence journal recovers interrupted file replacement on reopen and
|
||
returns a recovery error while earlier work remains unresolved. A confirmed
|
||
restart marks the saved generation applied only after a successful service job,
|
||
a matching complete runtime observation, and journaled verification-state write.
|
||
Restoring a backup does not restore runtime state: the running interface is
|
||
unknown until a later explicit restart and verification. Pending deleted-client
|
||
addresses remain reserved through Commit, reopen, and restore. See
|
||
[docs/BACKUP_FORMAT.md](docs/BACKUP_FORMAT.md) and
|
||
[docs/PERSISTENCE.md](docs/PERSISTENCE.md) for archive and recovery details,
|
||
and [docs/RUNTIME.md](docs/RUNTIME.md) for observation and restart boundaries.
|
||
|
||
## Vault and existing-client import library
|
||
|
||
`wireguard_admin::vault` provides WireGuard key handling, an encrypted versioned
|
||
vault bundle, caller-buffer client configuration parsing, and reconciliation
|
||
against a supplied server document. The source adapter can prepare an initial
|
||
encrypted bundle or explicitly import candidates into an existing prepared
|
||
bundle. These operations return in-memory data only: they do not install or save
|
||
a vault, edit source files or server configuration, Commit, or touch the VPN.
|
||
|
||
Directory scans use the resolved `client_source_directory` only. A candidate is
|
||
an immediate regular file whose name ends in `.conf` (case-insensitive); the
|
||
adapter does not recurse, follow symlinks, or read files larger than 1 MiB. A
|
||
scan is limited to 4,096 directory entries, 1,024 candidates, and 32 MiB total
|
||
input. Per-file failures are redacted and do not prevent other files from being
|
||
examined. Enumeration, read, or limit failures mark the scan incomplete. The
|
||
original files remain untouched. Adapter examples and behavior are covered with
|
||
synthetic temporary directories in `tests/vault_import.rs`.
|
||
|
||
## Client delivery and reissue
|
||
|
||
`Application::prepare_new_client` stages a dual-stack peer and encrypted key.
|
||
After a successful `commit`, `deliver_first_issue_file` can publish its first
|
||
configuration without a vault password during that same session; a failed file
|
||
publication can be retried to a newly selected destination. The first file is
|
||
mandatory. `deliver_first_issue_file_and_qr` optionally returns a QR matrix from
|
||
the same authorized bytes after file publication. Both success results carry an
|
||
activation warning unless this session has verified the exact installed saved
|
||
generation and its matching applied peer snapshot; historical verification and
|
||
unknown runtime state do not suppress it.
|
||
|
||
Later delivery uses `Application::reissue_client_file`, which takes the client
|
||
public key, a password for that action, a prepared destination, and an optional
|
||
QR choice. It freshly unlocks the installed saved vault each time, reads saved
|
||
server/settings bytes rather than draft state, preserves validated imported
|
||
parameters, and rejects blocked or stale records. It never reads original
|
||
plaintext client files as a fallback. The result reports a secret-free failure
|
||
stage and warns when the current saved peer set has not been verified as applied
|
||
in this live session. Historical verification timestamps do not suppress that
|
||
warning after reopen. File output uses mode `0600`, explicit overwrite
|
||
confirmation, and separate QR failure reporting. These APIs have synthetic
|
||
fixture coverage; the TUI password prompt and terminal QR rendering are not
|
||
implemented.
|
||
|