Building a role that grants exactly enough
Three real scenarios with the actual permission names, the two places least privilege collides with the product, and one built-in role that over-grants.
The three built-in roles cover most organisations. When they do not, you create a role and grant it exactly the permissions the job needs. This article works three real requests through to the actual permission names, and is honest about the two points where least privilege collides with how the product is built — because a role that is minimal and also unusable helps nobody.
Read The permission model first if you have not. In particular: matching is exact, there are no wildcards, and one membership carries exactly one role — so every permission a person needs must be on the single role you give them.
How a role is built
A role has a name and a description, and it belongs to your organisation. Names must be unique within it: a duplicate returns role already exists with HTTP 409, and renaming onto an existing name returns role name conflict. Omitting the name returns name is required.
A new role is created empty. That is not an oversight — the database trigger that hands the built-in roles their default grants matches on the exact role name, so admin, member and viewer get their sets and any other name gets nothing at all. You then add permissions one at a time, each identified by its full name such as siem:alerts.read. Omitting it returns permission_name is required; naming one that does not exist returns permission not found; adding one twice returns permission already assigned.
GET /api/v1/permissions the whole catalogue
GET /api/v1/roles/{roleID}/permissions roles.read
POST /api/v1/roles/{roleID}/permissions roles.write {"permission_name"}
DELETE /api/v1/roles/{roleID}/permissions/{permID} roles.writeThe rest of this article tells you what to put in the role. The two collisions at the end apply regardless of who does the clicking.
Someone who may read alerts but not act
A common request. A junior colleague, or an outsourced helpdesk, should see what is happening without being able to change anything. Grant the reads and nothing else.
siem:alerts.read View SIEM alerts
siem:rules.read View SIEM correlation rules
siem:dashboards.read View SIEM dashboards
siem:queries.read View SIEM saved queries
xdr:alerts.read View XDR alerts
xdr:incidents.read View XDR incidents
xdr:endpoints.read View XDR endpoints
xdr:telemetry.read View XDR telemetry
xdr:response_actions.read View XDR response actions
realtime:events.read Subscribe to realtime event streams
users.read View user profiles
members.read View organization membersWithhold, deliberately: siem:alerts.write, xdr:alerts.write, xdr:incidents.write and above all xdr:response_actions.execute, which is the permission that isolates a machine from the network.
Someone who may approve privileged access but not request it
This is the separation-of-duties request: a partner or director who signs off when somebody needs administrator credentials, without being a user of those credentials themselves. It is a good instinct and the permission catalogue cannot express it.
pam:access_requests.read View PAM access requests
pam:access_requests.write Raise and action PAM access requests
pam:policies.read View PAM access policies
pam:sessions.read View PAM sessions
users.read View user profiles
members.read View organization membersWithhold pam:credentials.read without exception. It is retrieval of the secret material itself and it is the single most sensitive permission in the catalogue — an approver has no need of it. Also withhold pam:sessions.write, pam:policies.write, everything under pam:rotation and everything under pam:discovery. What privileged access management is for explains why retrieval and approval are different jobs.
One thing you do not have to configure: granting privileged access is never automated. Not at any autonomy tier and not at any confidence level — the capability is not exposed to the model at all, so no approval can be produced by software on your behalf.
An auditor who may read evidence and nothing else
The narrowest of the three, and the one where a custom role earns its keep, because the obvious answer — give them viewer — grants far more than an auditor needs.
compliance:evidence.read View compliance evidence
compliance:frameworks.read View compliance frameworks
compliance:breaches.read View breach records
audit_logs.read View audit logsThat is the whole set. No alerts, no endpoints, no users, no PAM, nothing about billing. If your auditor also needs to see the organisation's own settings, add organizations.read — but read the warning first. The evidence bundle is what most audit questions are actually answered from, and it is covered by the first permission on the list.
One built-in role over-grants, and you should check yours
This section is the reason not to reach for viewer when you mean read-only. It is unflattering and it is important.
The intended policy for the built-in roles is recorded in a table in the database, and it is deliberate and well argued: viewer gets read actions only, and never a read that exposes secret material, money, or a security-administration surface. That table drives the trigger described in The permission model, and on that path the policy is honoured exactly.
There is a second, older mechanism that also runs when an organisation is created, and it grants a wider set than the table intends. On an organisation provisioned through that path:
| Role | Also receives | Why it matters |
|---|---|---|
viewer | pam:credentials.read, billing:subscriptions.read, billing:invoices.read | The first is retrieval of privileged credential material, which the written policy reserves to admin without exception. The other two expose what you pay. |
member | pam:credentials.read, pam:sessions.write, api_keys.read, api_keys.write, sso.read, ai:assistants.write, integration:webhooks.write, billing:subscriptions.read, billing:invoices.read | Credential retrieval again, plus the ability to mint an API key, read your single sign-on configuration, change what the AI assistant is allowed to reach for, and create an outbound webhook — which is a way to send your data somewhere else. |
The general lesson is worth stating plainly, because it is not specific to us: the name of a role is a claim, and the permission list is the fact. When somebody's access matters, read the list.
The ceiling on a custom role
Three administrative actions cannot be delegated to a custom role no matter which permissions you put on it. Adding or changing an organisation member, editing a role, and configuring single sign-on all additionally require the caller's role to be named exactly admin or delegated_admin. A role you called Access reviewer holding members.write will still be refused, with HTTP 403 and this message:
action requires elevated delegated role
That is a name comparison, not a permission check, and it is worth knowing before you spend an afternoon assembling a role that cannot work. If the job genuinely requires those three actions, the person needs admin, or a role named delegated_admin — and Delegated administration is candid about how much less that second option gives you than the name suggests.
What to do next
- The permission model — the resource table to pick names from, and the boundaries that do not hold.
- Who can see and do what — the built-in roles and the recommendation for a firm of a dozen people.
- Delegated administration — before you plan around scoping an administrator to part of your estate.