ACL v2 / RBAC (REST API/XO6)
ACL v2 is the access control system for the Xen Orchestra REST API and the XO6 UI. It lets you define exactly what each user or group can see and do — down to individual objects — without granting them full administrator access.
What changed from v1
The old ACL system (v1) allowed granting access to individual objects (a VM, an SR…). Simple, but limited: there was no way to say "this user can shutdown only VMs tagged qa". It also only covered XAPI objects — VMs, hosts, SRs, networks. Users, groups, backups, schedules, and jobs were out of scope.
ACL v2 introduces a full RBAC (Role-Based Access Control) model with effects, selectors, and an action hierarchy, covering the entire infrastructure including XO management objects.
ACL v2 is available through the REST API only. The JSON-RPC API (used by XO5) stays on ACL v1. Conversely, ACL v1 is not available on the REST API.
Core concepts
How it works
ACL v2 follows a deny-by-default model:
- XOA admins always have full access, regardless of any ACL configuration.
- Non-admin users start with zero access. They can only access objects they have been explicitly granted permission to.
- A
denyprivilege always takes precedence over anallowprivilege on the same action + resource + object combination.
The system is built around two building blocks:
| Concept | Description |
|---|---|
| Role | A named container for privileges. |
| Privilege | A rule inside a role: which action is allowed (or denied) on which resource, and optionally on which subset of objects. |
Roles
A role is just a label with a collection of privileges. You create a role once, add privileges to it, then assign it to as many users or groups as needed.
A user's effective privileges are the union of all privileges from all their direct roles and the roles of their groups.
Privileges
A privilege defines:
- resource — the type of object (e.g.
vm,backup-job,sr) - action — what operation is allowed or denied (e.g.
read,start,delete) - effect — whether the privilege grants (
allow) or blocks (deny) the action - selector (optional) — a filter expression to restrict the privilege to a subset of objects (complex-matcher format)
Action hierarchy
Actions use a : separator to form a hierarchy. A broader action automatically covers its children:
| Privilege action | Covers |
|---|---|
shutdown | shutdown:clean and shutdown:hard |
reboot | reboot:clean and reboot:hard |
update | update:tags, update:datasources, … |
* | every action on the resource |
The reverse is not true: granting shutdown:clean does not grant shutdown:hard.
Built-in template roles
Xen Orchestra ships with four ready-to-use role templates. They are immutable and automatically kept up to date on startup — they cannot be modified, deleted, or assigned directly.
To use them, copy a template into a new role and assign that copy to your users or groups. This ensures the built-in templates always stay up to date without affecting your custom configuration.
| Role | Description |
|---|---|
| Read only | Read access to the entire infrastructure and all XO objects. Cannot modify anything. |
| VMs power state manager | Can start, stop, reboot, pause, suspend, resume, and unpause VMs. |
| VMs creator | Can instantiate VM templates and create VDIs and VIFs. |
| VMs read only | Can only list and view VMs. |

Self endpoints
Some endpoints are always accessible to a logged-in user without any ACL privilege, as they only expose information about the user themselves:
| Endpoint | Description |
|---|---|
GET /rest/v0/users/me | Get your own user profile |
GET /rest/v0/users/me/privileges | List your own privileges |
GET /rest/v0/users/me/authentication_tokens | List your own authentication tokens |
POST /rest/v0/users/me/authentication_tokens | Create an authentication token for yourself |
me is a convenience alias — it is automatically redirected to /rest/v0/users/{your-id}.
The Swagger UI available at /rest/v0/swagger documents every endpoint with its required privileges. Endpoints with no declared privilege are admin-only.
Supported resources and actions
Actions are written using the exact string you pass in a privilege. A parent action (e.g. reboot) is a shortcut that covers all its children — see Action hierarchy.
Infrastructure resources
| Resource | Available actions |
|---|---|
vm | read, delete, export, pause, start, resume, snapshot, suspend, unpause, reboot:clean, reboot:hard, shutdown:clean, shutdown:hard, update:datasources, update:tags |
vm-snapshot | read, delete, export, update:tags |
vm-template | read, delete, export, instantiate, update:tags |
vm-controller | read, update:tags |
vdi | read, create, delete, boot, export-content, import-content, update:tags |
vdi-snapshot | read |
vdi-unmanaged | read |
vif | read, create |
vbd | read |
sr | read, import:vdi, import:vm, update:tags |
host | read, allow-vm, export:logs, update:tags |
pool | read, emergency-shutdown, rolling-reboot, rolling-update, create:network, create:vm, update:tags |
network | read, create, delete, update:tags |
pif | read |
pbd | read |
pci | read |
pgpu | read |
vgpu | read |
vgpuType | read |
vtpm | read |
sm | read |
gpuGroup | read |
XO management resources
| Resource | Available actions |
|---|---|
backup-job | read |
backup-archive | read |
backup-log | read |
backup-repository | read |
schedule | read, run |
restore-log | read |
proxy | read |
server | read, create, delete, connect, disconnect |
task | read, abort, delete |
alarm | read |
message | read |
User management resources
| Resource | Available actions |
|---|---|
user | read, create, delete, update:name, update:password, update:permission, update:preferences |
group | read, create, delete, update:name, update:users |
acl-role | read, create, delete, update:name, update:description, update:users, update:groups |
acl-privilege | read, create, delete, update:action, update:effect, update:resource, update:selector |
Concrete examples
Alice: QA operator scoped to tagged VMs
Alice needs to start and stop VMs in her test environment, but must not touch anything in production.
Create a QA Operator role with these privileges:
{ "resource": "vm", "action": "read", "effect": "allow", "selector": "tags:qa" }
{ "resource": "vm", "action": "start", "effect": "allow", "selector": "tags:qa" }
{ "resource": "vm", "action": "shutdown", "effect": "allow", "selector": "tags:qa" }
Attach the role to Alice. She can now manage QA VMs only. Any attempt on a VM without the qa tag is blocked with a 403.
If someone adds the qa tag to an existing VM, it immediately appears in Alice's scope.
This means a single tag change is enough to grant or revoke access to a resource, with no need to touch roles or privileges at all.
Bob: Snapshot only running VMs
Bob is allowed to snapshot VMs, but only while they are running — to avoid snapshotting stopped VMs that may be part of an automated maintenance process.
Create a Running VM Snapshot role with these privileges:
{ "resource": "vm", "action": "read", "effect": "allow", "selector": "power_state:Running" }
{ "resource": "vm", "action": "snapshot", "effect": "allow", "selector": "power_state:Running" }
Bob can see and snapshot any running VM. Stopped VMs are completely invisible to him.
Carol: Full VM access except production
Carol can do everything on VMs — except touch anything tagged
prod.
Create a Full VM Access (non-prod) role with these privileges. The * wildcard grants every action on a resource at once. Pair it with a deny to carve out an exception — deny always wins:
{ "resource": "vm", "action": "*", "effect": "allow" }
{ "resource": "vm", "action": "*", "effect": "deny", "selector": "tags:prod" }
Carol can start, stop, delete, snapshot any VM she wants. Production VMs are completely invisible to her — they never appear in her lists and any direct attempt returns a 403.
Walkthrough: creating and assigning a role
Step 1 — Create a role

Response:
{ "id": "e4b1f3c2-1234-5678-abcd-000000000001" }
Step 2 — Add privileges to the role

Step 3 — Assign the role to the user

The user can now list VMs.
To assign to a group instead (all group members inherit the role):

Selectors
By default, a privilege applies to all objects of the given resource type. The optional selector field narrows it down using the complex-matcher syntax — the same filter syntax used in the XO UI.
A selector is evaluated against each object's properties. If it matches, the privilege applies; otherwise it does not.
Common selector patterns
| Goal | Selector example |
|---|---|
| A specific object by its ID | id: <uuid> |
| All objects in a pool | $pool: <pool-uuid> |
| VMs tagged with a label | tags: <tag> |
| VMs by power state | power_state: Running |
| VMs created by a specific user | creation:creator: <user-id> |
Tips
- Start minimal. Add only the privileges a user actually needs. It is easy to add more later.
- Use groups. Assigning a role to a group avoids repeating the same assignment for every user.
- Combine
allowanddeny. When a user needs broad access with specific exceptions, grant with a wildcard privilege and carve out exceptions withdeny+ a selector. - Template roles are immutable. Copy them first before customizing.
- Endpoint permissions are visible in the Swagger UI (
/rest/v0/swagger). Endpoints without a declared privilege require admin access.