feature: the web service is an OpenID Provider, which signs the directory's users in to other systems, the clients being service accounts with redirect URIs.
Release / release (push) Successful in 13s
Release / release (push) Successful in 13s
This commit is contained in:
1 parent
d1d565b1d9
commit
8cac21845a
17 files changed
+1189
-58
No files matched your search
@@ -98,8 +98,8 @@ Context: OpenVPN needs user accounts with passwords, and the users are meant to
|
||||
system of the router, including IKEv2 EAP-TLS and WireGuard, which an OIDC provider cannot
|
||||
authenticate. Everything the router runs comes from the Ubuntu archive. slapd, its Python module
|
||||
`python3-ldap` and the OpenVPN plugin `openvpn-auth-ldap` are all in the archive; the plugin
|
||||
checks a password by binding as the user, so the hash scheme is slapd's alone. An OIDC provider
|
||||
can read the directory through its LDAP connector.
|
||||
checks a password by binding as the user, so the hash scheme is slapd's alone. The router's own
|
||||
OpenID Provider (ADR-37) signs the directory's users in to other systems.
|
||||
|
||||
Decision: The users are entries in slapd. The package keeps its own database,
|
||||
`dc=vpn-router,dc=local` in `/var/lib/ldap/vpn-router` (the path the slapd AppArmor profile
|
||||
@@ -979,7 +979,7 @@ Consequences: Peers follow their users: disabling a user drops the user's device
|
||||
directory's backup holds them. A peer cannot exist without a VPN user. A change restarts
|
||||
`wg-quick@wg0` through setup, which briefly interrupts the other peers.
|
||||
|
||||
## ADR-36: Passkeys sign in to the Router Manager only, verified by the router with python3-fido2
|
||||
## ADR-36: Passkeys sign in to the Router Manager and the OpenID Provider, verified by the router with python3-fido2
|
||||
|
||||
Context: Typing the password and a TOTP code at every sign-in to the Router Manager is tedious.
|
||||
WebAuthn needs a browser, HTTPS and a domain name; OpenVPN, IKEv2, WireGuard, SSH and sudo have no
|
||||
@@ -998,9 +998,48 @@ passkey sign-in gives the same tokens as `/auth`; as it binds no password, the r
|
||||
the user is enabled, not locked and not a service account. The begun steps are kept in the web
|
||||
service's memory for 2 minutes. The browser converts the options and answers with
|
||||
`PublicKeyCredential.parseCreationOptionsFromJSON`, `parseRequestOptionsFromJSON` and `toJSON`.
|
||||
The OpenID Provider's sign-in page (ADR-37) takes a passkey the same way.
|
||||
|
||||
Consequences: Passkeys are a convenience for the Router Manager; the password and code stay for
|
||||
everything else, the shell included. A changed `wan.local_fqdn` orphans every passkey. The
|
||||
Consequences: Passkeys are a convenience for the Router Manager and the OpenID Provider; the
|
||||
password and code stay for everything else, the shell included. A changed `wan.local_fqdn` orphans every passkey. The
|
||||
Router Manager on another name, or in development on `localhost`, cannot use them. Failed passkey
|
||||
sign-ins do not count towards the directory's lockout, but the sign-in calls are rate limited.
|
||||
Browsers without the JSON methods of WebAuthn Level 3 cannot add or use passkeys.
|
||||
|
||||
## ADR-37: The web service is an OpenID Provider built on python3-oauthlib; its clients are service accounts
|
||||
|
||||
Status: Accepted
|
||||
|
||||
Context: Other systems, such as dashboards, should sign the router's users in with the directory's
|
||||
passwords, TOTP codes and passkeys, without a second user store. The Ubuntu archive has no
|
||||
packaged identity provider. `python3-oauthlib` and `python3-jwt` are in main for noble and
|
||||
resolute; oauthlib implements the OpenID Connect flows and leaves the checks, the storage and the
|
||||
ID token's signature to the application. `python3-authlib` and `python3-jwcrypto` are in universe
|
||||
only. The web service already checks passwords and passkeys, rate limits sign-ins and keeps
|
||||
tokens in PostgreSQL, and Caddy serves it over HTTPS on `wan.local_fqdn`. ADR-3's HS256 key must
|
||||
not leave the router, but a relying party verifies an ID token itself.
|
||||
|
||||
Decision: The web service is the OpenID Provider, in `vpnrouter_oidc`, while `oidc.enabled` is
|
||||
true; its issuer is its HTTPS site, `https://<wan.local_fqdn>:<https.web_port>`, without the port
|
||||
on 443, and it answers the provider's paths only on `127.0.0.1`, where Caddy passes them. Only
|
||||
the authorization code flow with PKCE S256 and the refresh token grant are allowed. A client is a
|
||||
service account with redirect URIs, kept with the account in the new attributes
|
||||
`vpnRouterRedirectUri`, `vpnRouterPostLogoutRedirectUri` and `vpnRouterAllowedGroup` of
|
||||
`vpnRouterAccount`: its name is the client ID and its password the secret, checked with a bind.
|
||||
Allowed groups limit who may sign in; without them every user may. A registered client is
|
||||
trusted, so there is no consent page. The sign-in page is the web service's own, a Jinja2
|
||||
template with the password, the code and a passkey, so the provider works without the Router
|
||||
Manager. ID tokens are RS256, signed with an RSA key the web service makes on its first run
|
||||
(`/etc/vpn-router/oidc.key`), published as a JWK named by its RFC 7638 thumbprint; `sub` is the
|
||||
entry's `entryUUID`. Codes, access and refresh tokens and sessions are kept as their SHA-256 in
|
||||
the database of the refresh tokens, defined in `/usr/share/vpn-router/sql/oidc.sql` with
|
||||
procedures and functions the module calls; a process loads the file at its first connection. The
|
||||
operations that revoke the refresh tokens of `/auth` also revoke them, and every use of a code or
|
||||
token checks the user and the client's allowed groups again.
|
||||
|
||||
Consequences: The package depends on `python3-oauthlib` and `python3-jwt`. The provider needs
|
||||
HTTPS, a public name and the web service. Clients are managed like service accounts, by the CLI,
|
||||
`/service-accounts` and the Router Manager; a group a client allows cannot be removed, and renaming
|
||||
it renames it in the clients. The signing key does not rotate; replacing it invalidates every ID
|
||||
token issued. Wrong client secrets lock the client like any account. The implicit and hybrid
|
||||
flows, dynamic client registration and public clients without a secret are not offered.
|
||||
Reference in new issue
Block a user