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.
Splitting into more clusters is one answer to “several groups of people share
this platform”. The other is to share one cluster properly, which is cheaper and
is the right answer far more often than the cluster-per-tenant instinct
suggests.
Proxmox VE’s tool for that is the resource pool. It is genuinely useful and it
is routinely oversold, so this lesson does two things: builds a delegation that
works, and then states plainly what pools do not do.
What a pool is
The documentation is precise and short. A pool is “a set of virtual machines,
containers, and storage devices” that exists to simplify permission handling:
rather than setting permissions on each resource, you set them on
/pool/{poolid}, and they are inherited by all pool members.
That is the whole feature. A pool is:
A membership list of guests and storages.
An ACL path — /pool/<name> — that permissions can attach to.
A GUI grouping, so a tenant’s view is a folder rather than a search.
Building a delegated tenant
The working pattern is a group, a role, a pool, and ACLs on the pool path plus
the storages the tenant is allowed to consume.
Configuration changecreate the pool and its group— Changes access control and cluster configuration. Creates an empty pool and a group to hold the tenant's users. Nothing is delegated yet.
POOL="tenant-blue"
pveum pool add "$POOL" --comment "Blue team: delegated self-service"
pveum group add "$POOL-admins" --comment "Administrators for the blue tenant"
Configuration changea purpose-built tenant role— Changes access control. PVEVMAdmin is close to what a self-service tenant needs but grants more than most estates intend. Building the role explicitly means the privilege list is a document you can review. Note what is absent: VM.Migrate, VM.Config.HWType, Sys.* and anything under Permissions.
Configuration changegrant the role on the pool, and only the storages the tenant may use— Changes access control. Two grants: the pool path covers every current and future member guest, and the storage paths are what allow disk allocation. Grant the storage narrowly — a tenant with Datastore.AllocateSpace on / can fill every storage in the cluster.
Configuration changeput resources into the pool— Changes cluster configuration. --vms and --storage take comma-separated lists; --delete on the same command removes the listed members instead of adding them. A guest can belong to at most one pool.
POOL="tenant-blue"
pveum pool modify "$POOL" --vms 141,142,205 --storage blue-rbd
pveum pool list --poolid "$POOL"
pveum pool modify takes --allow-move, defaulting to 0. It governs whether
a resource already belonging to another pool may be moved into this one by the
same call.
Leaving it at the default is the safer choice and it is worth understanding why.
A guest silently changing pools changes which ACLs apply to it. With
--allow-move enabled and a scripted pool assignment, a mistake in a VMID list
does not error — it moves somebody else’s guest into your tenant’s pool, and
with it, access.
Enable it deliberately, for a specific reorganisation, and turn it off again.
What pools do not isolate
This is the section to read to a stakeholder before agreeing to a multi-tenant
design. A pool is an authorisation boundary. It is not any of the following.
Not isolated
What actually happens
Where the real control lives
CPU
Tenant A’s guests compete with tenant B’s for host cores
Per-guest cores, cpulimit and cpuunits; node placement (Part XVII)
Memory
Overcommit and ballooning are node-wide; one tenant’s pressure is everyone’s
Per-guest memory, no overcommit for shared clusters, node separation
Storage capacity
A shared storage is filled by whoever gets there first
Separate storages per tenant, monitored per storage
Storage IOPS
A noisy tenant degrades the shared backend
Per-disk mbps/iops limits, separate backends
Network
Guests on the same bridge/VLAN can reach each other regardless of pool
SDN zones and firewall — the next lesson
The node
A tenant with Sys.Console or node-level access sees everything on that node
Do not grant node-level privileges to tenants
Cluster visibility
/cluster/resources filtered by permission still reveals node names and structure
Accept it, or use separate clusters
Backups
A cluster backup job is cluster configuration, not tenant configuration
Per-pool backup jobs exist as a job selection mode; retention is still yours
The blast radius
A pmxcfs, quorum or upgrade event hits every tenant at once
Separate clusters — Part XXVII lesson 1
Choosing the boundary for a tenant
Tenant looks like
Right boundary
Because
A team inside your organisation, cooperative, shared change window
Pool + SDN zone on a shared cluster
Cheapest to run; one upgrade, one backup regime, one on-call
A team that needs guaranteed capacity
Pool + dedicated storage, and node placement or HA groups for compute
Capacity is enforceable at the storage layer; compute is enforceable by placement
A customer with a contract, a change freeze, or a compliance boundary
Separate cluster
The upgrade unit and the blast radius are contractual, and neither is delegable inside a cluster
Tenants who must not be able to reach each other’s control plane at all
Separate cluster
A cluster’s nodes trust each other; there is no partial trust
A cost centre or a project
Tags, not pools
Pools are exclusive; a guest has one tenant but many attributes
Key takeaways
A pool is a membership list of guests and storages plus an ACL path
/pool/<name>. Permissions set there are inherited by all members.
Proxmox VE does not support per-pool resource limits or quotas. Pools are
exclusively a permission grouping mechanism. Any quota you have promised is
enforced outside PVE or by dedicated storage.
Build the tenant role explicitly rather than reusing PVEVMAdmin, and grant
it on /pool/<name> plus only the storages the tenant may consume.
pveum pool modify --vms --storage manages membership; --delete removes the
listed members; --allow-move (default 0) should stay off except during a
deliberate reorganisation.
A guest belongs to at most one pool. Use tags — with registered-tags and
user-tag-access in datacenter.cfg — for cost centre, environment and
application.
Pools do not isolate CPU, memory, storage capacity, IOPS, network
reachability, node access or blast radius. Each of those has a different
control, and two of them only have one: separate storage, and separate
clusters.
Choose pool plus SDN zone for cooperative internal teams; pool plus dedicated
storage where capacity is promised; a separate cluster where the contract,
the change freeze or the trust boundary is real.
Knowledge check
Knowledge check · 5 questions
Q1. A customer is sold a "2 TB" tier and the implementation puts their guests in a resource pool on a shared Ceph storage. What is wrong?
Q2. Two tenants share one cluster, each with their own pool. Which of these does the pool boundary genuinely NOT isolate? Select all that apply.
Q3. Why is --allow-move on pveum pool modify left at its default of 0 in most estates?
Q4. A guest can belong to several pools at once, which makes pools a good mechanism for tracking cost centre and environment alongside tenancy.
Q5. A prospective tenant has a contractual change freeze during their financial year end and a compliance requirement that no other customer administrator can reach their control plane. Pool, or separate cluster?
Passing score: 75%. Answers are checked in this browser.