---
title: "Roles and permissions"
---

# Roles and permissions

Reference for Neural Inverse Govern's permission grammar, account roles, resource roles, bindings, custom roles, sharing and the escalation guard, with the permissions each governance area uses.

Access in Govern is granted with roles bound to nodes of the organisation's directory. This page is the reference for how roles, bindings and permissions fit together, and which permissions the governance areas use.

## The model

| Term | Meaning |
|---|---|
| Node | A directory node: organisation, business unit, service, team, project or sub-project. |
| Permission | `<resource>:<verb>`, for example `models:admin` or `iam.reviews:decide`. A resource is one or more lowercase segments joined by dots. |
| Role | A named set of permission patterns, plus optional composite roles. Built-in roles are versioned in code; custom roles belong to one organisation. |
| Binding | A principal (user, group or service account), a role and a node, with an optional CEL condition, an optional expiry and a state (`active` or `eligible`). Bindings apply to the node and everything below it. |

A granted permission can be a wildcard: `<resource>:*`, `*:<verb>` or `*:*`. A required permission is always a concrete name from the catalog. `GET /api/v1/permissions` lists the catalog (filter by `prefix`, `privileged` and `risk`), and `GET /api/v1/me/permissions` answers the caller's effective permissions on a node.

## Account roles

Account roles are bound on the organisation node. One person can hold several.

| Role | Holds | Cannot |
|---|---|---|
| Owner | Everything, including the Owner-reserved actions | |
| Admin | Users, groups, settings and every resource | The Owner-reserved actions |
| Security and compliance | Reads the audit trail, evidence, access configuration, policies and security posture; manages compliance, privacy requests and access reviews | Use or change code-facing resources; grant roles |
| Billing | Billing, usage and quotas | Anything else |
| Member | Only themselves (profile, own sessions, devices and keys) and the runtime entry points that deliver what is assigned to them (`models:read`, `skills:use`, `harness:read`) | Read or list any resource not shared with them |
| Read-only (all) | Reads everything, sensitive data included | Never a default; granted explicitly |

**Owner-reserved actions** are denied to everyone without a standing Owner grant: changing the payment method (`billing.payment_method:manage`), the spending cap, the support plan, closing the account (`account:close`), and granting or revoking Owner (`iam.owner:grant`, `iam.owner:revoke`). A just-in-time or break-glass activation of an Owner binding does not count. At least one Owner is always kept, and only an Owner can make another Owner.

The console shows account roles and custom roles on **Access > Roles**.

## Resource roles

Resource roles are bound on a project node or on one object. Each level includes the one before.

| Role | `use` / `read` / `write` / `secrets` / `manage` |
|---|---|---|---|---|---|
| User | yes | | | | |
| Viewer | yes | yes | | | |
| Editor | yes | yes | yes | yes | |
| Manager | yes | yes | yes | yes | yes |

- `use`: use the resource for one's work without seeing its configuration, for example call models through a connection or connect to an MCP server.
- `read`: read the configuration. Secret values are never returned after they are saved; model connection keys show only a hint and version.
- `write`: change the configuration.
- `secrets`: replace a secret, write-only.
- `manage`: grant and revoke resource roles, delete or disable the resource.

Approval is never part of a resource role. It is a separate permission in every area (`mcp:approve`, `agentpolicy:approve`, `agents:approve` and others), and nobody can approve their own request.

Shareable resource types include projects, model connections (`models.connections`), MCP servers (`mcp.servers`), skills, harness packs (`harness.packs`), Context spaces, vault paths, workspaces, sandboxes and agent policy rule sets. Membership of a project gives User on it.

### What lists and direct reads show

Lists return only the objects the caller holds at least `use` or `read` on. A direct request for an object the caller can neither use nor read answers `404`, also for writes, so a refusal never confirms that an object exists.

### Sharing

People with Manager on an object share it from the object's page in the console, or with the API:

| Route | Who |
|---|---|
| `GET /api/v1/access/resources/{type}/{id}/effective-access` | Anyone signed in: their own level on the object |
| `GET /api/v1/access/resources/{type}/{id}/sharing` | Viewer: who has access and how |
| `POST /api/v1/access/resources/{type}/{id}/sharing` / Manager: grant `{principal_type, principal_id, level}`; audited `access.share.granted` |
| `DELETE /api/v1/access/resources/{type}/{id}/sharing/{binding_id}` / Manager: revoke; audited `access.share.revoked` |

A share cannot exceed the granter's own level, cannot go to the granter or a group they belong to, and cannot come from authority that exists only through a just-in-time activation. Requests for access are on [Just-in-time access](https://neuralinverse.com/docs/govern/jit-access/#resource-access-requests).

## Bindings

| Route | Permission |
|---|---|
| `GET /api/v1/access/bindings` / `iam.bindings:read` (filters `node_id`, `principal_type`, `principal_id`, `role_id`, `state`) |
| `POST /api/v1/access/bindings` / `iam.bindings:create` on the node, plus the escalation guard |
| `GET /api/v1/access/bindings/{id}` / `iam.bindings:read` |
| `PUT /api/v1/access/bindings/{id}` / `iam.bindings:update`, plus the escalation guard |
| `DELETE /api/v1/access/bindings/{id}` / `iam.bindings:delete`; the last administrator cannot be removed |

Binding body: `node_id`, `principal_type` (`user`, `group` or `service_account`), `principal_id`, `role_id`, `state` (`active` or `eligible`), `condition` (CEL), `condition_title`, `expires_at`, `requires_approval`, `max_activation_minutes` (1 to 10080), `break_glass`, `membership_bound` and `description`. Mutable objects carry an `etag`; updates and deletes need `If-Match` and answer `409` on a mismatch. Every write returns a revision token (`rv1.<n>`); a client that sends it back in `X-Keystone-Access-Revision` gets answers computed at that revision or later.

### Conditions

Conditions are CEL, compiled and type-checked when saved. They can read `request.time`, `request.method`, `request.path`, `request.ip`, `request.mfa_age_seconds`, `resource.id`, `resource.kind`, `resource.path`, `resource.labels` (only `access/` labels), `principal.type`, `principal.id`, `principal.email` and `principal.groups`. An allow binding grants only when its condition is true; a deny applies when its condition is true or cannot be evaluated.

## Custom roles

| Route | Permission |
|---|---|
| `GET /api/v1/access/roles`, `GET /api/v1/access/roles/{id}` / `iam.roles:read` |
| `POST /api/v1/access/roles` / `iam.roles:create` |
| `PUT /api/v1/access/roles/{id}` / `iam.roles:update` |
| `DELETE /api/v1/access/roles/{id}` / `iam.roles:delete` |
| `GET /api/v1/access/roles/{id}/versions` / `iam.roles:read` |

Body: `{"name", "description", "permissions": [...], "composites": [role ids]}`. Permissions must be catalog names or wildcard patterns over the catalog. Built-in roles are read-only, every change records a version, and a role that is bound or used as a composite cannot be deleted. Creating or changing a role requires holding, with standing bindings on the organisation node, everything the role would grant.

## The escalation guard

Creating or changing a binding requires, at the target node:

1. `iam.bindings:create` (or `update` or `delete`).
2. Holding every permission the role grants.
3. The role being on the node's delegation allow-list; see [Access guardrails](https://neuralinverse.com/docs/govern/access-guardrails/).
4. For roles that themselves grant roles: authority from a binding on the organisation node.
5. A node keeps at least one administrator.
6. Privileged roles bind only to users or to groups with assigned membership.
7. No binding that breaks a separation-of-duties rule.
8. No binding for yourself or a group you belong to.
9. Authority that comes only from a just-in-time or break-glass activation can create only bindings that expire no later than the activation.

Invitations follow the same rule: an invitation can give an account role only if the inviter could grant it.

## Permissions by area

These are the permissions the governance pages of these docs refer to. Owner and Admin hold all of them through `*:*`. In this table, `iam.sod:read/manage` is shorthand for the two permissions `iam.sod:read` and `iam.sod:manage`; the slash is not part of any name.

| Area | Permissions |
|---|---|
| Access | `iam.roles:*`, `iam.bindings:*`, `iam.denypolicies:read/manage`, `iam.ceilings:read/manage`, `iam.delegation:read/manage`, `iam.sod:read/manage`, `iam.settings:read/update`, `iam.principals:read/manage`, `iam.activations:read/request/approve`, `iam.breakglass:read/review`, `iam.reviews:read/manage/decide/export`, `iam.access:analyze` |
| Identity Center | `sso.connections:*`, `sso.domains:*`, `sso.enforcement:*`, `sso.domainusers:*`, `sso.permissionsets:*`, `sso.assignments:*`, `sso.mappings:*`, `sso.sessions:*`, `scim:manage`, `scim:read`, `ldap:read/update/create` |
| API keys and service accounts | `apikeys:read/create/delete`, `directory.serviceaccounts:read/manage` |
| Model access and the AI Gateway | `models:read` (use), `models:view` (read configuration), `models:write` (catalog, assignments, defaults, budgets, routes), `models:admin` (connections, policy, gateway settings, keys, guardrails, rate limits, logs), `models:keys` (provider keys) |
| Agent policy | `agentpolicy:read`, `agentpolicy:write`, `agentpolicy:approve` |
| Approvals | `approvals:read`, `approvals:approve`, `approvals:admin` |
| Third-party tool controls | `controls:manage`, `security:read` |
| Harness packs | `harness:read`, `harness:publish`, `harness:assign`, `harness:experiment` |
| Console assistant | `assistant.conversations:*`, `assistant.proposals:*`, `assistant.settings:getsettings/updatesettings` |
| Audit | `audit:read`, `audit:create` |

## Legacy organisation roles API

The older routes under `/api/v1/organizations/{id}/roles` (and `.../members/{membership_id}/roles`) still work and need `roles:read`, `roles:create`, `roles:update` or `roles:delete`. Role assignments made through them pass the same escalation guard. Prefer `/api/v1/access/*` for new automation.
