fix: the PKI is kept in ou=pki of the router's directory instead of files under /etc/vpn-router/pki, and the router's site-to-site certificate names only the identities its connections present, and /ca/bundle gives the certificate bundle of a CA.
Release / release (push) Successful in 29s

This commit is contained in:
slawek committed 2026-10-25 23:03:03 +01:00
1 parent e11c88f0de
commit 448ce05b3a
10 files changed
+796 -509

No files matched your search

+44 -10
View File
@@ -152,8 +152,8 @@ Status: Accepted
Context: Users are managed from the command line, by an operator at a terminal, and through
`/users` of the web service, by the Router Manager. Both must apply the same rules to names,
passwords and person attributes, and both change the directory and the PKI, whose state is one
file, so two changes must not run at the same time. The web unit is sandboxed with
passwords and person attributes, and both change the directory and the PKI, whose CRL numbers and
CRLs two changes must not write at the same time. The web unit is sandboxed with
`ProtectSystem=strict`.
Decision: `vpnrouter_users.py` holds the user operations, the checks and a session that takes a
@@ -162,9 +162,9 @@ lock and the connection of the user manager account. The web service imports it
the output, text for people and JSON with `--json`. The web unit allows writing the paths the
operations need: `/run/vpn-router` for the lock, its `RuntimeDirectory`, which systemd creates
before the service starts, also before setup has run, and keeps when it stops, as setup's state
files are there too; `/etc/vpn-router/pki` for the certificates and the PKI's state, and
`/etc/swanctl/x509crl`, `/etc/openvpn/server` and `/var/lib/vpn-router/pki-publish` for the
CRLs a revocation signs. The PKI module, `vpnrouter_pki.py`, works the same way for `/ca`,
files are there too, and `/etc/swanctl/x509crl`, `/etc/openvpn/server` and
`/var/lib/vpn-router/pki-publish` for the copies of the CRLs a revocation signs; the PKI itself is
in the directory (ADR-32). The PKI module, `vpnrouter_pki.py`, works the same way for `/ca`,
`vpn-router-ca` and `vpn-router-setup`, and its lock is the users' lock, as adding and removing
a user issue and revoke a certificate.
@@ -757,8 +757,8 @@ of common name and the subject alternative names a certificate may have; `vpn-se
`vpn-user` are issued by the router only, so no certificate for another use comes from the P2S
CA. The module `vpnrouter_pki.py`, with `python3-cryptography` from the Ubuntu archive, builds
the keys, certificates, CSRs and CRLs in the processes that need them, as the user module does
(ADR-6); the settings are the `pki` section of `vpn-router.json` and the state is
`pki/state.json`. Keeping the root key off the router is recommended, not required: while it is
(ADR-6); the settings are the `pki` section of `vpn-router.json`, and the CAs and the
certificates are kept in the router's directory (ADR-32). Keeping the root key off the router is recommended, not required: while it is
on the router a new issuing CA is signed at once, and while it is not the CA gets its key and a
CSR, signed offline and imported with `vpn-router-ca` or `/ca`. The root key itself crosses
neither the API nor the Manager. For a certificate of something other than the router, the router
@@ -808,14 +808,17 @@ secret to distribute. Azure's VPN gateway authenticates site-to-site connections
keys only.
Decision: A connection's `auth` is `psk`, the default, or `certificate`. With `certificate` the
router presents one site-to-site certificate of its `s2s` CA, whose names are `wan.local_fqdn`,
the public address and the internal address, so it fits every `local_id_mode`; the peer's
router presents one site-to-site certificate of its `s2s` CA, whose names are `wan.local_fqdn` and
the local identities the connections with `certificate` use, the public or the internal address of
their `local_id_mode`, and no address no connection presents, such as an internal address the peers
never see; the peer's
certificate must name the connection's `id` and be issued by the router's `s2s` CA or, when the
connection has `remote_ca`, by that CA, its PEM certificate kept in the connection and copied to
`/etc/swanctl/x509ca/s2s-<name>.pem`. A peer without a PKI gets its certificate from the router.
Consequences: The connection Azure's gateway needs stays `psk`, so the platform writes nothing
new. The router's site-to-site certificate is issued again when an address it names changes. The
new. The router's site-to-site certificate is issued again when the set of names it needs changes,
such as when a connection's `local_id_mode` or its address changes. The
router does not check a remote CA's revocations unless strongSwan can fetch the CRL its
certificates name.
@@ -861,3 +864,34 @@ Manager shows which one is in effect.
Consequences: The first setup run with HTTPS starts the installation and serves HTTPS on the run
that follows it. The key of Caddy's repository is trusted as downloaded over HTTPS, the way Caddy's
installation instructions do it. Going back to the archive's Caddy is a manual downgrade.
## ADR-32: The PKI is kept in the router's directory
Status: Accepted
Context: The CAs, their keys and CRLs, the inventory of the certificates issued and their
revocations, and the router's and the users' certificates and keys need a store. Files with a
JSON state file cannot be searched, and are copied apart from the users the certificates belong
to. The router runs slapd, which holds the users and is provisioned on every
configured router (ADR-10), and PostgreSQL, which holds the refresh tokens and the metrics, may
be another server (`web.database`) and is in a backup only with `backup.metrics`. RFC 4523
defines `pkiCA` with `cACertificate` and `certificateRevocationList`, and `userCertificate`, which
OpenLDAP's core schema includes.
Decision: The PKI is held in `ou=pki` of the router's directory. A CA is an entry of the package's
class `vpnRouterAuthority` with `cACertificate` and `certificateRevocationList`, its key, its CSR,
its CRL number, the source of the root CRL and the time it was retired; a certificate is an entry
of `vpnRouterCertificate` named by its serial number under its CA, with `userCertificate`, its
kind, template, names, expiry and revocation, and the key of a router or user certificate. A
user's certificate is also the `userCertificate` of the user's entry. An ACL lets no account read
`vpnRouterPrivateKey`; only root, the database's root DN, does, through the local socket. A
retired CA keeps its entry, renamed, so its certificates stay in the inventory. A root supplied
from outside, by cloud-init or by hand, is placed as files before the first setup with a platform,
which imports and removes them. strongSwan, OpenVPN, Caddy and the system's trust store read files,
so setup and every revocation write them from the directory. Setup provisions the directory before
the PKI; without the directory it leaves the PKI and its files as they are and configures the rest.
Consequences: `slapcat` writes the users and the PKI into every backup in one consistent copy, and a
restore brings both back together. The PKI depends on slapd, as the users already do, and not on
PostgreSQL. The directory holds the CA keys, so it is as sensitive as the CA itself. The schema
grows by the package's PKI attributes and classes, which setup adds to slapd's configuration.