- Python 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| debian | ||
| src/pmx_cork_access | ||
| tests | ||
| .gitignore | ||
| LICENSE | ||
| pyproject.toml | ||
| README.md | ||
pmx-cork-access
The auth provider of the pmx-cork suite: the backend behind the replaceable
auth seam, and the libpve-access-control analog. It reimplements the Proxmox
identity and authorization primitives and presents them as one provider
object.
| Module | Mirrors |
|---|---|
auth |
PVE::AccessControl: the PVEAuthCookie ticket (RSA), CSRF (HMAC-SHA256), API tokens (verified against pmxcfs over the IPC transport of pmx-cork-pmxcfs) |
userid |
PVE::AccessControl and PVE::Auth::Plugin: the user@realm and user@realm!token grammar |
permissions |
PVE::RPCEnvironment: the ACL walk over /etc/pve/user.cfg |
cluster |
the peer's certificate, read from /etc/pve/nodes/<node>/ (the address to dial comes from pmx-cork-pmxcfs's members) |
keycache |
content-keyed caching for the key files every request reads |
provider |
PROVIDER, the object [auth] provider resolves to |
Cross-node TLS trust
PVE pins a peer's certificate by the SHA-256 of the leaf it serves, and this
provider does the same thing with the same input: the fingerprint is taken from
/etc/pve/nodes/<node>/pveproxy-ssl.pem, or pve-ssl.pem when the node carries
no custom certificate, and handed to aiohttp as a Fingerprint.
It is a pin, not chain validation and not a hostname check. That is not a
shortcut but the model itself: PVE::APIServer::AnyEvent returns 1 from its
verify callback for every depth above the leaf and defers the whole decision to
PVE::CertCache::check_cert_fingerprint.
Reproducing it matters for one supported configuration in particular. A node
with its own pveproxy-ssl.pem, from Let's Encrypt for instance, has a
certificate that does not chain to the cluster CA at all. Verifying a chain
instead would refuse exactly the peers PVE accepts.
An unreadable certificate means no fingerprint, and the hop fails closed with a 502 rather than dialling unverified. Reads are cached by content, so a renewed certificate takes effect on the next request without a watcher or a restart.
The provider object
PROVIDER is what [auth] provider names, and the runtime's
load_auth_backend() is the one place that turns the name into an object. The
object provides the auth methods (authenticate, is_enabled,
check_privileges, check_api_permissions, token_owner), peer resolution
(remote_node_ip, peer_ssl, cert_hostname) and credential_headers.
The surface is duck-typed. The resolved object is injected, as app.state.AUTH
and through task_api.set_auth, so no other layer imports an auth package or
looks up which backend is configured. Resolution fails loudly at boot.
Replacing the backend
[auth]
provider = "pmx_cork_access:PROVIDER" # the default
To run another identity and RBAC backend, ship a package that exports an
object with the same methods and point [auth] provider at it. A missing
package or an object without the methods the first request needs refuses
service. The permission vocabulary stays PVE-shaped (ACL paths, the route
permissions= spec); a provider replaces the mechanism, not the spec plugins
are written against.
Ships as python3-pmx-cork-access. Depends on pmx-cork-tasks,
pmx-cork-pmxcfs and python3-cryptography.