Proxmox VEXIII · Proxmox Backup ServerPBS security
PBS users, ACLs, tokens and datastore permissions
What you'll learn
- Navigate the PBS object-path tree and predict the effective permission at any path
- Choose the right built-in role for a PVE cluster, an auditor and a sync partner
- Create API tokens and explain why a token can never exceed its user
- Build the append-only arrangement that stops a compromised PVE node deleting its own backups
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
Most Proxmox estates add PBS to the cluster with a root@pam credential
because that is what the setup guide shows and it works immediately. It is
also the configuration in which an attacker who gets root on any node of the
cluster can delete every backup of every guest, and then encrypt the guests.
The permission model is the control that prevents that, and it is the only one that survives a fully compromised hypervisor. Firewall rules, network segmentation and immutable-storage claims all help, but if the credential stored on the compromised node can prune the datastore, they help less than you think.
This lesson is therefore organised around one question: what can the credential on your PVE node actually do to the datastore?
The object-path tree
PBS addresses everything it protects with filesystem-like paths. Permissions are granted by attaching a role to a path for an authentication identity.
| Path | Covers |
|---|---|
/ | Everything |
/datastore | All datastores |
/datastore/{store} | One datastore |
/datastore/{store}/{ns} | One namespace inside a datastore |
/remote | All configured remotes |
/system/network | Host network configuration |
/tape/ | Tape devices, pools and jobs |
/access/users | User administration |
/access/openid/{id} | A specific OpenID realm |
Permissions granted at a shorter path can propagate down the tree:
Permissions of higher levels (shorter paths) can optionally be propagated down within this hierarchy.
The propagate flag defaults to enabled. That default is convenient and it
is where over-permissioning creeps in: DatastoreAdmin on /datastore with
propagation on is a grant over every datastore that exists and every one
created later.
The roles, and what each is for
| Role | Grants | Use it for |
|---|---|---|
NoAccess | Nothing | Explicitly denying a subtree below a broader grant |
Admin | Anything, on the object path assigned | Human administrators, scoped as narrowly as the job allows |
Audit | View status and configuration; change nothing | Monitoring systems, auditors, junior on-call |
DatastoreAdmin | Anything on existing datastores | A backup administrator who should not create datastores |
DatastoreAudit | View metrics, settings and content listings; cannot read the actual data | Capacity dashboards and compliance evidence without data access |
DatastoreReader | Inspect a datastore or namespace and perform restores | A restore-only operator account |
DatastoreBackup | Back up and restore owned backups | The PVE cluster credential |
DatastorePowerUser | Back up, restore and prune owned backups | A cluster that manages its own retention. Note what that implies |
RemoteAdmin | Anything on remotes | Managing the remote configuration |
RemoteAudit | View remote settings | Monitoring sync configuration |
RemoteSyncOperator | Read data from a remote | The account a pull sync job runs as |
TapeAdmin / TapeOperator / TapeAudit / TapeReader | Tape operations at descending privilege | Tape workflows |
The two rows that carry the whole security argument are DatastoreBackup and
DatastorePowerUser. They differ by exactly one capability: prune.
Creating the accounts
set -euo pipefail
# A dedicated user for the cluster, in the built-in PBS realm.
proxmox-backup-manager user create pve-cluster-a@pbs \
--comment 'Backup identity for production cluster A'
# A token belonging to that user. Tokens are what automation should carry;
# they can be revoked without disturbing the user or any other token.
proxmox-backup-manager user generate-token pve-cluster-a@pbs backup
# => { "tokenid": "pve-cluster-a@pbs!backup", "value": "REPLACE_ME_ONCE_ONLY" }
# Grant on the namespace only, not the datastore.
proxmox-backup-manager acl update /datastore/store1/prod-cluster-a \
DatastoreBackup --auth-id 'pve-cluster-a@pbs!backup'
# The token needs the grant; so does the user, because the effective
# permission is the intersection of the two.
proxmox-backup-manager acl update /datastore/store1/prod-cluster-a \
DatastoreBackup --auth-id 'pve-cluster-a@pbs'# proxmox-backup-manager user permissions 'pve-cluster-a@pbs!backup' --path /datastore/store1/prod-cluster-aPrivileges with (*) have the propagate flag set
Path: /datastore/store1/prod-cluster-a
- Datastore.Backup (*)
- Datastore.Read (*)Illustrative output
Wiring it into PVE
set -euo pipefail
# On the PBS server:
# proxmox-backup-manager cert info | grep -i fingerprint
pvesm add pbs pbs-main \
--server pbs1.example.com \
--datastore store1 \
--namespace prod-cluster-a \
--username 'pve-cluster-a@pbs!backup' \
--password 'REPLACE_ME_ONCE_ONLY' \
--fingerprint 'aa:bb:cc:dd:ee:ff:00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00:11:22:33:44:55:66:77:88:99' \
--content backup
pvesm status --storage pbs-mainset -euo pipefail
proxmox-backup-manager datastore update store1 \
--prune-schedule 'daily 04:00' \
--keep-daily 14 --keep-weekly 8 --keep-monthly 12
proxmox-backup-manager datastore update store1 --gc-schedule 'sat 03:00'Roles for the other actors
| Actor | Path | Role | Reasoning |
|---|---|---|---|
| PVE production cluster | /datastore/store1/prod-cluster-a | DatastoreBackup | Write and restore its own; never delete |
| Monitoring / dashboards | /datastore | DatastoreAudit | Needs usage and job status; must not be able to read backup contents |
| Restore-only operator | /datastore/store1 | DatastoreReader | Can inspect and restore anything; cannot write or prune |
| Backup administrator | /datastore | DatastoreAdmin | Full control of existing datastores, no host administration |
| Pull sync from a remote | /remote/{remote}/{store} | RemoteSyncOperator | Read the remote; the local write privilege is granted separately |
| Standalone host client | /datastore/store1/hosts | DatastoreBackup | Same argument as the cluster, at host granularity |
Sync jobs deserve a note because their privileges are split across two sides.
A pull job needs Remote.Read on /remote/{remote}/{remote-store} plus
Datastore.Backup on the local target, and additionally Datastore.Prune if
it uses remove-vanished. A push job needs Remote.Audit and
Remote.DatastoreBackup on the target, plus read or backup privileges on the
source, and Remote.DatastorePrune for remove-vanished.
Knowledge check
Knowledge check · 4 questions
Q1. A newly created API token authenticates but every operation is denied, while the owning user has DatastoreAdmin on the datastore. What is the cause?
Q2. A PVE cluster credential is given DatastoreBackup on its namespace instead of DatastorePowerUser. What changes? Select all that apply.
Q3. DatastoreAudit is a suitable role for a monitoring system that should report datastore usage and job status without being able to read backup contents.
Q4. Which sync direction leaves the primary site holding no credential that can write to the off-site copy?
Passing score: 75%. Answers are checked in this browser.