Skip to main content
RunBook Academy

Proxmox VEXV · Security & HardeningAccess control

Authentication realms: LDAP, AD and sync jobs

Advanced⏱ ~28 minpveumldapsearch

What you'll learn

  • Configure an LDAP or AD realm with TLS, a bind account and a correctly scoped base DN
  • Map directory groups onto Proxmox groups so authorisation follows directory membership
  • Run pveum realm sync with --dry-run and read the diff before committing it
  • Choose a remove-vanished policy and understand what each option does to a departing user

Prerequisites

Verified against Proxmox VE 9.2.4 · Proxmox Backup Server 4.2.5 · Ceph Squid / Tentacle · Debian 13 (Trixie) · Linux kernel 7.0 (PVE 9.2 default) · 2026-08-12

Not yet marked complete on this device.

A realm answers one question — is this person who they claim to be — and nothing else. It does not decide what they can do; that is the ACL model, and it stays entirely separate. The value of getting realms right is that joiners and leavers stop being a Proxmox task.

The failure this lesson exists to prevent is specific and common: an estate where the directory is the source of truth for identity everywhere except the hypervisor, so a person who left three months ago still has a working pve account with PVEVMAdmin on the production pool.

The realms you can configure

TypeBacking storeUse it for
pamLocal Linux users in /etc/passwdroot@pam only
pve/etc/pve/user.cfgService accounts and token owners
ldapAny LDAPv3 directoryHuman accounts, non-Microsoft directory
adActive DirectoryHuman accounts, Microsoft directory
openidAn OIDC providerHuman accounts behind an SSO IdP

pam and pve are not a scaling problem so much as an evidence problem. A local account has no lifecycle owner outside Proxmox, so nothing outside Proxmox will ever tell you it should be gone. Keep them for the two cases that genuinely cannot use the directory: root@pam, and service identities that own API tokens.

Configuring the realm

Four things matter and the rest is detail: the servers, the transport, the bind account, and the base DN.

Configuration changean Active Directory realm over LDAPS
AD_DOMAIN='corp.example.com'
BIND_DN='CN=svc-proxmox,OU=Service Accounts,DC=corp,DC=example,DC=com'
BASE_DN='OU=Staff,DC=corp,DC=example,DC=com'
GROUP_DN='OU=Groups,DC=corp,DC=example,DC=com'

pveum realm add corp --type ad \
--domain "$AD_DOMAIN" \
--server1 dc01.corp.example.com \
--server2 dc02.corp.example.com \
--port 636 \
--secure 1 \
--verify 1 \
--capath /etc/ssl/certs \
--bind-dn "$BIND_DN" \
--base-dn "$BASE_DN" \
--group-dn "$GROUP_DN" \
--comment 'Corporate AD, staff OU only'

The bind password is supplied interactively or with --password, and it is stored under /etc/pve/priv/ where only root can read it. It is also replicated to every node by pmxcfs, which is correct — every node authenticates independently — and worth knowing when you scope the bind account: it exists on every node in the cluster, so treat it as a cluster-wide credential.

Four options carry more weight than their length suggests.

--secure 1 with --port 636 is LDAPS. Without it the bind password and every username crosses the network in the clear. There is no reason to run a realm without TLS in 2026; if the directory does not offer it, that is a directory problem to escalate, not a Proxmox setting to skip.

--verify 1 validates the directory’s certificate. It is not the default. A realm with --secure 1 and --verify 0 encrypts the traffic and accepts any certificate, which stops passive capture and does nothing about an active attacker. Turning verification on and pointing --capath at the CA bundle — or --cacert at an internal CA file — is the difference between transport encryption and authenticated transport.

A narrow --base-dn. Scoping to the OU that holds staff accounts rather than the domain root means a sync cannot pull in service accounts, disabled accounts in a tombstone OU, or a contractor OU nobody told you about. It is also much faster on a large directory.

A read-only bind account. The bind account needs to read user and group objects and nothing more. It should not be a domain admin, and it should be excluded from any policy that expires or rotates it silently, because when it stops working nobody can log in.

Mapping directory groups onto Proxmox groups

This is the part that turns a realm from an authentication convenience into an authorisation mechanism.

Proxmox does not read AD group membership at permission-check time. The sync job reads it, creates a matching Proxmox group, and populates its membership. Your ACLs then reference the Proxmox group. The chain is:

AD group → synced PVE group → ACL entry → privileges on a path.

Change someone’s AD group membership and the next sync moves them between PVE groups; their permissions change without anybody touching an ACL. That is the entire point.

Configuration changebind ACLs to synced groups, once
pveum acl modify /pool/production --groups 'pve-vm-admins' --roles PVEVMAdmin
pveum acl modify /              --groups 'pve-auditors'  --roles PVEAuditor
pveum acl modify /nodes         --groups 'pve-node-ops'  --roles PVESysAdmin

The group names on the Proxmox side are whatever the directory group names sync to. Naming the AD groups with a pve- prefix is worth doing on day one: it makes the AD side self-documenting, and it means a search of the directory for who can administer the hypervisor returns an answer.

The sync job

pveum realm sync reads the directory and reconciles PVE users and groups against it. It is the operation that carries risk, because it can delete things.

Configure its defaults on the realm so that a scheduled run and a manual run behave identically:

Configuration changeset the sync defaults on the realm
pveum realm modify corp \
--sync-defaults-options 'scope=both,enable-new=0,remove-vanished=acl;properties' \
--user-classes 'user' \
--user-filter '(&(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))' \
--group-filter '(&(objectClass=group)(cn=pve-*))' \
--sync_attributes 'email=mail,firstname=givenName,lastname=sn'

Reading those left to right:

  • scope=both syncs users and groups. users or groups alone are for staged rollouts and for directories where groups come from somewhere else.
  • enable-new=0 creates newly discovered users in a disabled state. They exist, they appear in the GUI, and they cannot log in until someone enables them. On a first sync against a large directory this is the difference between an inventory and an access grant.
  • remove-vanished is the leaver policy, covered below.
  • --user-filter is doing real work in that example: the userAccountControl bit-and filter excludes accounts disabled in AD, so a disabled AD account never becomes an enabled PVE user.
  • --group-filter restricts the sync to groups whose name starts with pve-, which keeps several thousand irrelevant AD groups out of user.cfg.
  • --sync_attributes maps directory attributes onto PVE user properties, so the email that backup-failure notifications go to is the one in the directory.

Always dry-run first

Read-only / Safepreview the reconciliation
pveum realm sync corp --dry-run 1

Read the output before you commit it. Two numbers matter more than the rest: how many users it would create, and how many it would remove. A sync that proposes to remove most of your users has almost always got a filter wrong or lost its connection to a part of the directory tree — that is a configuration bug presenting as a mass deletion, and the dry-run is where you catch it.

Read-only / Safea dry run that should stop you
$ pveum realm sync corp --dry-run 1
starting sync for realm corp (dry-run)
users:  found 3, created 0, updated 3
groups: found 2, created 0, updated 2
vanished users: 41 (would remove: acl, properties)
sync finished (dry-run, nothing written)

Illustrative output

The leaver policy

remove-vanished takes a semicolon-separated list of what to clean up when a user or group is no longer returned by the directory query. The three values, and what each one actually means for the departing person:

ValueEffectThe risk it leaves
(unset)Nothing is removedThe account persists with all its ACLs. This is the state that leaves a leaver with PVEVMAdmin.
aclACL entries referencing the principal are deletedThe user object remains but grants nothing. Auditable, reversible, safe.
propertiesSynced attributes not present in the directory are clearedEmail and name go stale-free; no authorisation change.
entryThe user or group object is deleted from user.cfgImmediate and complete — and it removes the evidence along with the access.

acl;properties is the policy to default to. It removes the access on the next sync, keeps the user object so an audit can still see that the account existed and what it used to hold, and is undone by re-adding one ACL if the removal was wrong.

entry is defensible when a compliance requirement demands that identities be deleted rather than deactivated, and it should be a deliberate decision recorded somewhere, not a default someone copied.

Scheduling it

The sync is a datacenter-level job, configured under Datacenter → Permissions → Realms → realm → Sync options, with the schedule set on the realm. A daily sync is the usual cadence — it bounds how long a leaver keeps access to one day, which is what most access-control policies actually ask for.

Do not schedule a sync that has never been dry-run with its current filters. And send its notifications somewhere a human reads: a sync that has been failing for six weeks looks exactly like a sync that has nothing to do.

Common mistakes

  • --secure 1 without --verify 1. Encrypted and unauthenticated. Set --capath or --cacert and turn verification on.
  • Base DN at the domain root. Slow, and it pulls in every service and disabled account in the directory.
  • No --dry-run before changing a filter. The dry run is where a mass removal is a number on a screen instead of an incident.
  • remove-vanished=entry on a scheduled job. The sync’s own failure mode looks identical to a mass departure, and entry makes it destructive.
  • Assuming an AD group change revokes access immediately. It revokes at the next sync. Disabling the account revokes at the next login attempt.
  • A bind account subject to the normal password-rotation policy. When it expires, nobody can log in, and the error message does not say why.

Key takeaways

  • Realms authenticate; ACLs authorise. Changing one never changes the other.
  • Map directory groups onto PVE groups and bind ACLs to the groups. After that, joiners and leavers are a directory operation.
  • enable-new=0 makes a first sync an inventory rather than an access grant.
  • remove-vanished=acl;properties removes access, keeps evidence, and survives a sync that misfires. entry does not.
  • Always --dry-run 1 after changing a filter, a base DN or the remove-vanished policy, and read the removal count first.
  • The fast revocation is disabling the directory account, because authentication is live and authorisation is a snapshot.

Knowledge check

Knowledge check · 4 questions

  1. Q1. An engineer is removed from the pve-vm-admins group in Active Directory at 09:00. The realm sync runs daily at 02:00. When does their Proxmox access actually end?

  2. Q2. On an LDAP or AD realm, --secure 1 encrypts the connection while --verify 1 is what validates the certificate the directory presents, so a realm with --secure 1 and --verify 0 will accept any certificate.

  3. Q3. Why is remove-vanished=acl;properties a safer default for a scheduled sync than remove-vanished=entry? Select all that apply.

  4. Q4. You are running the first sync against a corporate directory with several thousand accounts. Which sync option most reduces the risk of that first run?

Passing score: 75%. Answers are checked in this browser.