feature: site_to_site holds any number of named site-to-site connections, which /site-to-site lists, adds, changes and removes.
Release / release (push) Successful in 12s
Release / release (push) Successful in 12s
This commit is contained in:
1 parent
a79510a02f
commit
4a5b15a559
22 files changed
+843
-351
No files matched your search
@@ -199,10 +199,15 @@ that a secret is set tells a reader more than it needs.
|
||||
|
||||
Decision: The configuration that `vpn-router-setup` writes for the web service has no secret
|
||||
options at all. They are recognised by name: `psk`, `database`, whose connection string may hold
|
||||
a password, and options with `secret`, `password`, `token` or a `_key` ending in the name.
|
||||
a password, and options with `secret`, `password`, `token` or a `_key` ending in the name. The
|
||||
names are checked at every level, so the settings of each site-to-site connection lose their
|
||||
`psk` too; an object is kept whatever its name, so a connection named like a secret is still
|
||||
shown.
|
||||
|
||||
Consequences: No secret reaches the web service's state file or any answer of the API. A client
|
||||
cannot tell whether a secret is set. A new secret option needs a name that matches.
|
||||
Consequences: No secret reaches the web service's state file or any answer of the API. Through
|
||||
`/config` a client cannot tell whether a secret is set; `/site-to-site` says whether each
|
||||
connection has a key (ADR-25), as an admin managing connections needs to know. A new secret
|
||||
option needs a name that matches.
|
||||
|
||||
## ADR-9: The Router Manager is a separate package with a small Python server
|
||||
|
||||
@@ -536,8 +541,8 @@ receiver. The router already runs PostgreSQL for the refresh tokens (ADR-15).
|
||||
|
||||
Decision: A service of its own, `vpn-router-metrics`, takes a sample every minute with `psutil`
|
||||
(`python3-psutil`) and the VPN readers it shares with the web service (`vpnrouter_status`). It
|
||||
keeps the samples in the router's database, in three detail tables (`metrics_system`,
|
||||
`metrics_network`, `metrics_vpn`). Each detail table has hourly, daily, monthly and yearly summary
|
||||
keeps the samples in the router's database, in four detail tables (`metrics_system`,
|
||||
`metrics_network`, `metrics_vpn`, `metrics_site_to_site`, see ADR-25). Each detail table has hourly, daily, monthly and yearly summary
|
||||
tables, with the average and the maximum of each value per period, written when the clock passes a
|
||||
period from the level below with `INSERT ... ON CONFLICT DO NOTHING`, so a stopped service catches
|
||||
up. Garbage collection runs on start and once a day, not with every write, and deletes the rows
|
||||
@@ -577,3 +582,86 @@ the router; deleting the file and running setup changes it. A user who already h
|
||||
taken over; setup fails until `metrics.service_account` names another. A disabled account stays
|
||||
disabled. A scraper on the external interface over plain HTTP sends the password in the clear, so
|
||||
`metrics.listen` stays `internal` unless HTTPS is used.
|
||||
|
||||
## ADR-24: The Router Manager upgrades the router's packages in a transient unit outside its own
|
||||
|
||||
Status: Accepted
|
||||
|
||||
Context: An admin should upgrade `vpn-router` and `vpn-router-manager` from the Router Manager. The
|
||||
upgrade restarts the process that starts it: the manager's postinst restarts
|
||||
`vpn-router-manager.service`, and the router's restarts `vpn-router-web` and `vpn-router-setup`. A
|
||||
child of the manager would be stopped with the manager's cgroup in the middle of dpkg, leaving
|
||||
packages half configured, and the manager's unit cannot run apt at all, since `ProtectSystem=strict`
|
||||
makes `/usr` and `/var/lib/dpkg` read-only. The package lists are updated by a cron job, not by the
|
||||
manager.
|
||||
|
||||
Decision: The manager starts the helper `/usr/lib/vpn-router-manager/upgrade` with `systemd-run` as
|
||||
the transient unit `vpn-router-manager-upgrade`, of its own cgroup and without a sandbox, and does
|
||||
not wait for it. The helper:
|
||||
|
||||
- finishes an interrupted dpkg run with `dpkg --configure -a`;
|
||||
- runs `apt-get install --only-upgrade` of the two packages, non-interactive, keeping changed configuration files, with `needrestart` suspended, and waiting for the dpkg lock that the cron job may hold;
|
||||
- records the state and the result in `/var/lib/vpn-router-manager/upgrade.json`, replaced by a rename, and the output in `upgrade.log`.
|
||||
|
||||
A restarted manager reads them again. A state of running without an active unit is shown as interrupted. The manager reboots the router the same way, as a transient timer `vpn-router-manager-reboot` 5 seconds later, so the answer reaches the browser first. Only members of `admins`, as the router's `/account` answers, may start either.
|
||||
|
||||
Consequences: The fixed unit name allows one upgrade at a time. The page loses the manager and the
|
||||
router's web service for a while during an upgrade and reads again until they answer. Sessions
|
||||
survive in PostgreSQL. The manager can upgrade only the system it runs on, so a manager on another
|
||||
host upgrades that host's packages, not the router's. The operating system's other packages are
|
||||
left to unattended-upgrades.
|
||||
|
||||
## ADR-25: Site-to-site connections are a map of named connections, edited through the API and applied by setup
|
||||
|
||||
Status: Accepted
|
||||
|
||||
Context: The router had one IPsec site-to-site tunnel, the `remote` section, run as the swanctl
|
||||
connection `remote-site`, with the local identity mode in `wan` and the local subnets in `local`.
|
||||
A router often links more than one site, each with its own peer, subnets and key, and an admin
|
||||
should add them without a shell. The install answers and the Cloud Platform describe one
|
||||
connection, and the platform rewrites `vpn-router.json` when it rebuilds the VM.
|
||||
|
||||
Decision: `site_to_site` maps a connection name to its settings: `addrs`, `id`, `cidrs`,
|
||||
`local_cidrs`, `local_id_mode`, `psk` and `psk_file`. `remote` and `wan.local_id_mode` are gone,
|
||||
without a fallback for the old format. The name, a lowercase letter followed by at most 30
|
||||
lowercase letters, digits and hyphens, names the swanctl connection, its child and its secret
|
||||
`ike-psk-<name>`, so it is a valid swanctl section name and stays the same while the connection
|
||||
lives. The install answers and the Cloud Platform write the connection `remote-site`, the first
|
||||
one, so its name is the one the tunnel always had.
|
||||
|
||||
- **Local settings per connection:** each connection has its own `local_cidrs` and
|
||||
`local_id_mode`, as each peer expects its own traffic selectors and identity. `wan.local_fqdn`
|
||||
stays the router's one name, used by the `fqdn` mode, resolved once for the `public_ip` mode,
|
||||
and used by HTTPS, road-warrior and OpenVPN. `local.cidrs` stays the subnets the router
|
||||
routes, masquerades and offers to road-warrior and OpenVPN clients.
|
||||
- **One file:** `vpn-router-setup` writes every connection that is ready to
|
||||
`/etc/swanctl/conf.d/site-to-site.conf`, with the proposals and timers the one tunnel had, and
|
||||
removes the file when none is. The NAT exemptions pair each connection's `local_cidrs` with its
|
||||
`cidrs`.
|
||||
- **Editing:** the status web service serves `/site-to-site` to members of `admins` and admin
|
||||
tokens, like `/users`. It never returns a key, only whether one is set, and takes a new key only
|
||||
when one is given. `vpn-config-edit` edits the same map. Both read, check with the validation
|
||||
of `vpn-router-setup` and write `vpn-router.json` holding one lock, replacing the file in one
|
||||
step, so neither loses the other's change.
|
||||
- **Applying:** the web service restarts `vpn-router-setup` without waiting for it, the one
|
||||
place that renders, loads and opens the firewall, so a change through the API takes the same
|
||||
path as a change by hand.
|
||||
- **Metrics per connection:** the metrics service keeps, per connection, whether it is up, the
|
||||
bytes and packets per second through its child SAs and the seconds its IKE SA has been up, in
|
||||
a detail table of its own, `metrics_site_to_site`, keyed by the connection's name, with the
|
||||
summaries and retention of the other tables (ADR-22). One row per connection keeps the values
|
||||
of a tunnel together and lets the set of connections change without changing the schema;
|
||||
`metrics_vpn` counts only clients. swanctl's child SA counters start again at a rekey, so the
|
||||
service keeps rates computed between two samples, treating a lower counter as counted from
|
||||
zero, and `/metrics` and the OTLP push serve them as gauges rather than counters that would
|
||||
appear to reset.
|
||||
|
||||
Consequences: A configuration with `remote` is refused, so the package and a configuration in
|
||||
the new format go together. The status shows each connection. A rate across a rekey misses the
|
||||
traffic of the old child SA since the previous sample. A renamed connection starts a new series.
|
||||
A connection added through the API lives in
|
||||
`vpn-router.json` only; the Cloud Platform's rebuild of the VM writes the file again with its
|
||||
one connection, dropping the others. A change through the API is answered before setup has
|
||||
applied it, so a configuration that setup cannot apply shows in the setup state, not in the
|
||||
answer. A connection with a key file keeps it until a key is given through the API, which then
|
||||
replaces the file.
|
||||
Reference in new issue
Block a user