proxkey holds a Proxmox API token and installs SSH keys into root accounts. This document states what it protects, what it does not, and how to report a problem.
Please report security issues privately through GitHub's private vulnerability reporting on this repository, rather than opening a public issue.
Include the version (proxkey version), your Proxmox version, and the smallest
reproduction you can manage. Expect an acknowledgement within a week.
Your SSH private key never exists as a file. It is generated in, and never
leaves, the Secure Enclave. proxkey only ever handles the public key. Copying
~/.ssh/ off a stolen laptop yields nothing usable, and there is no passphrase
to brute-force. Every SSH authentication is gated by Touch ID or the device
password, enforced in hardware.
The API token is never written to disk in plaintext. It lives in the macOS
Keychain, stored through the Security framework rather than by shelling out to
/usr/bin/security — so the secret never appears in a process argument list, and
the resulting Keychain item's access control list names the proxkey binary
itself. Other programs must prompt you before they can read it. Rebuilding
proxkey changes its code identity and will prompt once more; that is the
mechanism working.
Configuration and SSH config are written 0600 in 0700 directories, and the
managed SSH block lives in its own ~/.ssh/config.d/proxkey.conf rather than
being spliced into your hand-written config.
The API connection is authenticated. Proxmox ships a self-signed certificate,
so proxkey setup shows you the certificate's SHA-256 fingerprint alongside the
command that prints the same fingerprint on the server, and pins it once you
confirm. After that, a certificate that does not match is refused. This matters
because the token travels in a plain Authorization header: an unauthenticated
TLS connection hands your token to anyone on the network path.
SSH to a PVE node fails closed on an unknown host key. Node addresses come
from the cluster API, so blindly accepting a new host key would let a bad API
response redirect the connection. You verify the fingerprint once, or opt into
trust-on-first-use per endpoint with "trust_new_hosts": true.
A compromised Mac. If an attacker is running code as you, they can ask the Secure Enclave to sign (subject to your Touch ID prompt), prompt you for Keychain access, or simply wait for you to authenticate. proxkey raises the cost of key theft; it does not survive a compromised endpoint.
A malicious or compromised Proxmox server. proxkey trusts the API it is pointed at. A hostile server can report false IP addresses and cause you to write SSH config entries pointing somewhere unexpected. Certificate pinning ensures you are talking to the server you pinned, not that the server is honest.
Anything the token can do. The token is a real credential. Scope it with
proxkey token, which emits a least-privilege recipe, and revoke it with
pveum user token remove if a machine is lost.
Keys already installed. Revoking the API token stops further provisioning but
does not remove keys from guests. Use proxkey revoke first.
optional_host_permissions is https://*/* because Proxmox runs on arbitrary
private hostnames that cannot be enumerated in advance. Two things bound it:
- Permission is requested for one specific origin at a time, from a user gesture in the popup — never for the whole pattern.
- The background worker refuses to register the content script on any origin that
is not one of the endpoints in your own
config.json.
The extension is intended to be loaded unpacked from this repository. It is not published on the Chrome Web Store.
Content scripts run inside the Proxmox web UI. The background service worker
accepts exactly one message type from them (wizard-armed) and rejects every
other, including all native-host RPC. It also derives the target endpoint from
the sender's own origin rather than from anything the message claims.
Arming the create-wizard checkbox starts a watcher that is scoped to a single VM ID where the wizard exposes one, and otherwise to one guest and a 15 minute TTL. An unbounded watcher would install your key on any guest created in that window, including guests created by a colleague or by automation. Guests outside the scope are reported as skipped and left untouched.
The least-privilege token recipe deliberately omits VM.GuestAgent.Unrestricted,
which permits arbitrary command execution inside guests. proxkey uses it only to
create /root/.ssh when missing; without it that single call fails and
provisioning continues.
- Run
proxkey tokenand use the scoped token it describes — notroot@pam. - Confirm
proxkey doctorreports a pinned certificate for every endpoint. - Keep
insecure_tlsunset. Ifdoctorwarns about it, runproxkey trust <endpoint>. - Scope the token to a pool rather than
/vmsif you only manage some guests. - Set a token expiry:
pveum user token add ... --expire <unix-timestamp>. - Before decommissioning a Mac, run
proxkey revokefor each managed guest, then remove the token withpveum user token remove.
Security fixes are applied to the latest release only.