feature: users sign in to the Router Manager with passkeys, and console login needs a TOTP token, so a user without one is refused the shell, SSH and sudo.
Release / release (push) Successful in 14s

This commit is contained in:
slawek committed 2026-10-26 08:35:10 +01:00
1 parent 91cc64d6a6
commit 90db6d46a2
10 files changed
+408 -62

No files matched your search

+35 -3
View File
@@ -945,12 +945,18 @@ so slapd's otp overlay and password policy apply as for the Router Manager: the
by the code, and the lockout. Members of `vpn-router-console` get sudo with that password. SSH
accepts it only while `ssh.ldap_login` is set, in a `Match Group` drop-in of sshd. Switching console
login off keeps the `posixAccount`, hidden by nslcd's filter, so the uid and the home stay the
user's; leaving `admins` switches it off.
user's; leaving `admins` switches it off. A console reaches root through sudo, so a password alone
must not open one: console login needs a TOTP token. Switching it on is refused without one, and
the token is checked at use rather than only when it is switched on, because an administrator can
remove it later: the shell's ticket and every minute of an open shell check it, nslcd's
`pam_authz_search` requires `oathTOTPUser`, and removing the token ends the sessions of the user's
own POSIX account.
Consequences: Each administrator's shell, SSH session and sudo run as the administrator, logged
under the administrator's name. The directory becomes part of the system's name service through
nslcd, and the system knows only the accounts with console login on. A user enrolled for TOTP types
the code after the password at the SSH and sudo prompts. Homes are created at the first login and
nslcd, and the system knows only the accounts with console login on. The user types the code
after the password at the SSH and sudo prompts. An administrator whose console login was switched
on before the token was required is refused until enrolling. Homes are created at the first login and
are not removed with the user. A password is changed through the directory, not with `passwd`.
## ADR-35: WireGuard peers are the devices of the VPN users, kept in the directory
@@ -972,3 +978,29 @@ endpoint is, choosing the user for each.
Consequences: Peers follow their users: disabling a user drops the user's devices, and the
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
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
browser, and the sudo PAM module for security keys needs the key at the router. The router signs
users in (`/auth`) and keeps them in its directory. The standard library cannot read CBOR or COSE
keys; Ubuntu packages Yubico's python-fido2 in noble (1.1) and resolute (2.0), whose server API is
the same once the JSON mapping of WebAuthn Level 3 is switched on, which 2.0 always uses.
Decision: A passkey is a discoverable credential with user verification of the relying party
`wan.local_fqdn`, with the user name as its user handle, so the sign-in needs no name. The router
registers and verifies passkeys with python3-fido2 in `vpnrouter_passkeys`; the origin must be
HTTPS on that name, which python-fido2 checks. Each passkey is a JSON value of the multi-valued
`vpnRouterPasskey` on the user's entry, with the public key only. Registration needs the current
password and code, so a session alone cannot add a lasting way in; removal needs neither. A
passkey sign-in gives the same tokens as `/auth`; as it binds no password, the router checks that
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`.
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
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.