TL;DR

In Keycloak: Clients → Create client → OpenID Connect, Client ID proxmox, Client authentication On, Standard flow On, Valid redirect URIs https://pve.example.local:8006 and https://pve.example.local:8006/*. Copy the secret from the Credentials tab.

On a Proxmox node:

1
2
3
4
5
6
7
pveum realm add keycloak --type openid \
  --issuer-url https://id.example.local/realms/lab \
  --client-id proxmox \
  --client-key '<client-secret>' \
  --username-claim preferred_username \
  --autocreate 1 \
  --comment 'Keycloak'

Users log in as alice@keycloak. They are created on first login, with no permissions; permissions are still Proxmox ACLs:

1
2
3
pveum group add sso-admins
pveum acl modify / --groups sso-admins --roles Administrator
pveum user modify alice@keycloak --groups sso-admins     # after their first login

How it works

Proxmox has supported openid realms since PVE 7. From issuer-url it downloads /.well-known/openid-configuration and takes the endpoints from there; the login screen shows the realm in the dropdown and the Login button redirects to Keycloak. On the way back, the value of the claim you picked in username-claim becomes the user <claim>@<realm>.

username-claim accepts any claim name. Keycloak sends preferred_username by default (it comes from the username mapper in the profile client scope), so the extra mapper old guides added to expose a claim called username is not needed. If you prefer the email, --username-claim email.

Keycloak, step by step (26)

  1. Realm. Use the one you have (lab in the example). The issuer is https://id.example.local/realms/lab. Since Keycloak 17 there is no /auth/ in the path; if you copy /auth/realms/... from an old guide, discovery fails.
  2. Clients → Create client.
    • Client type: OpenID Connect. Client ID: proxmox. Name: whatever you like.
    • Capability config: Client authentication On (confidential client, with secret). Standard flow On. Everything else Off: Direct access grants, Implicit flow, Service accounts, Authorization.
    • Login settings: Root URL https://pve.example.local:8006; Valid redirect URIs https://pve.example.local:8006 and https://pve.example.local:8006/*. Web origins empty: it is a redirect flow, there is no CORS.
  3. Credentials → Client secret. That is the --client-key.
  4. Groups (optional). Clients → proxmox → Client scopes → proxmox-dedicated → Add mapper → By configuration → Group Membership: Name groups, Token Claim Name groups, Full group path Off, Add to ID token and Add to userinfo On.

Proxmox, step by step

Through the GUI: Datacenter → Permissions → Realms → Add → OpenID Connect Server: Issuer URL, Realm (the short name, keycloak), Client ID, Client Key, Username Claim preferred_username, Autocreate Users. Or the pveum realm add from the TL;DR; the configuration lands in /etc/pve/domains.cfg and replicates across the cluster.

With groups coming from Keycloak, on recent PVE 8 releases and on PVE 9 (pveum realm add --help tells you whether your version has --groups-claim):

1
pveum realm modify keycloak --groups-claim groups --groups-autocreate 1

Each group in the claim is created as <group>-keycloak and the user joins them on every login; you assign the ACLs to those groups.

Test before touching anything else: login screen → Realm Keycloak → Login → you come back authenticated and pveum user list shows alice@keycloak.

Traps

  • Invalid parameter: redirect_uri in Keycloak: the URL you typed in the browser (name, port 8006, https) is not in Valid redirect URIs. If you use both the IP and the FQDN, add both.
  • The node must trust Keycloak’s certificate, not just your browser. With an internal CA: copy the .crt to /usr/local/share/ca-certificates/ and run update-ca-certificates.
  • issuer-url has to match exactly the iss in the tokens: https, no trailing slash, /realms/<realm>.
  • Time. A skewed clock invalidates tokens; chrony on the nodes.
  • Do not let users edit their own username in Keycloak (a warning from Proxmox’s own docs): renaming yourself to root is switching accounts in Proxmox.
  • Do not set --default 1 until it works, and keep root@pam as the emergency door: if Keycloak is down, the openid realm cannot authenticate anyone.
  • API and CLI. OIDC users have no password in Proxmox; for Terraform, Ansible, or pvesh from outside create a token: pveum user token add alice@keycloak automation --privsep 0.

Reference: User Management — OpenID Connect in the Proxmox guide and client creation in the Keycloak documentation.