Getting Started

Roles, RBAC and Permissions

How Versus authorizes every action — a five-level default role hierarchy, resource-scoped custom roles, fine-grained permission strings, external directory group mappings, and server-side enforcement that the API applies regardless of what the UI shows.

Every action in Versus — viewing a device, running a workflow, reading a secret, approving a certificate — is authorized against the signed-in user's permissions. Authorization is decided in the back end, on every request, so it holds the same whether the caller is the web UI, a script hitting the REST API, or an integration. The UI is role-aware (it only offers what you can do), but it is never the thing that enforces the rule.

Versus models access with two complementary constructs:

  • Default roles — a system-defined privilege hierarchy of five levels (Guest through Super Admin) that grants a broad, sensible bundle of permissions.
  • Scoped roles — custom roles you build from individual permissions and pin to specific resources (virtual servers, partitions, or devices).

A user's effective permissions are the union of their default role and every scoped role assigned to them.


The default role hierarchy

Five default roles ship with the platform. Each has an integer level (1–5); higher levels strictly include the operational reach of lower ones. Default roles are system-defined and read-only — you assign them, but you don't edit their permission sets.

LevelRoleWhat it can do
5Super AdminFull control: auth-backend config, role and group mapping, user management, all devices and resources.
4Network AdminManage devices, partitions, virtual servers, and certificates. Cannot configure auth backends or manage users/roles.
3OperatorDay-to-day operational changes to applications and virtual servers; run workflows. No structural device changes.
2ViewerRead-only access to everything in scope. Cannot make any change.
1GuestDefault fallback — dashboard and applications view only.

The level is what the coarse-grained authorization checks compare against. The API exposes four privilege gates that map directly to these levels — IsSuperAdmin (≥5), IsNetworkAdmin (≥4), IsOperator (≥3), and IsViewer (≥2) — plus a tenant-scoped IsTenantAdmin for multi-tenant deployments.


Permissions

Beneath the roles is a flat catalog of permission strings, each namespaced as <area>.<action>. A few representative entries:

devices.view        devices.create      devices.edit       devices.delete
workflows.view      workflows.run       workflows.manage
certs.view          certs.issue         certs.approve      certs.manage
vault.view          vault.read          vault.manage
firewall.view       firewall.edit       firewall.manage
users.view          users.create        users.manage
roles.view          roles.manage        auth.configure
audit.view          system.view         system.manage

The catalog also covers IPAM, security scanning, migrations, integrations, F5OS operations, consolidation planning, cloud-WAF exception handling, collector administration, self-healing, and the ITSM/Service Desk. Fetch the authoritative list at runtime:

GET /api/default-roles/permissions_list/
→ { "permissions": [ "devices.view", "devices.create", ... ] }

Each default level maps to a fixed permission bundle:

  • Level 5 — every permission in the catalog.
  • Level 4 — everything except auth.configure, users.manage, roles.manage, and the platform-provisioner permission. A Network Admin runs the estate but can't reshape identity or access policy.
  • Level 3 — an operational subset: the .view permissions plus applications.create/edit, workflows.run, certs.issue, and similar day-to-day actions.
  • Level 2 — every .view/.use permission and nothing else.
  • Level 1 — no permissions.

Fine-grained checks in the API test for a specific string rather than a level. A view protected by require_perm('devices.edit') grants access to anyone whose effective permissions include devices.edit, no matter how they obtained it — from their default level or from a scoped role.


Scoped roles — permissions bound to resources

Default roles are estate-wide. When you need "operator, but only on these two virtual servers," you build a scoped role:

  1. Give it a name and a hand-picked list of permission strings.
  2. Attach one or more resource scopes — each is a resource_type of vs (virtual server), partition, or device, targeting either a specific resource ID or a wildcard (all resources of that type).
  3. Assign it to users.
POST /api/scoped-roles/
{
  "name": "DMZ VIP Operator",
  "description": "Operate the two internet-facing VIPs only",
  "permissions": ["applications.view", "applications.edit", "workflows.run"],
  "scopes": [
    { "resource_type": "vs", "resource_id": 1043, "resource_name": "vip-www" },
    { "resource_type": "vs", "resource_id": 1044, "resource_name": "vip-api" }
  ]
}

Scoped roles are managed by Network Admin and above. Because a user's effective permissions are the union of their default role and all their scoped roles, scoped roles add capability — you use them to grant targeted reach on top of a modest baseline (for example, a Viewer who also operates one application team's VIPs).


How effective permissions are computed

Two properties on a user's profile drive every decision:

  • effective_level — the level of the assigned default role, or a legacy fallback if none is set.
  • effective_permissions — the sorted union of the default role's permissions and the permissions of every scoped role assigned to the user.

A permission check is then simply perm in effective_permissions. This resolution lives in one place in the back end, so the web UI, the API, and automation all get the identical answer.

The signed-in user can read their own resolved access at:

GET /api/users/me/
→ {
    "role": "operator",
    "role_level": 3,
    "role_name": "Operator",
    "permissions": [ "applications.edit", "workflows.run", ... ],
    "scoped_roles": [ { "id": 7, "name": "DMZ VIP Operator", ... } ],
    "is_tenant_admin": false
  }

The front end uses exactly this payload to decide which navigation items and buttons to render — which is why the UI only ever offers actions the API would also authorize.


Directory groups and external identity

Versus authenticates against pluggable auth backends: Local, AD / LDAP, SAML / SSO, and TACACS+. Each is configured once (host, base DN, attribute maps, and so on), with sensitive values — bind passwords, shared secrets, client secrets — encrypted at rest, never stored in plaintext config. Backends are tried in priority order at sign-in. Configuring them requires Super Admin (auth.configure).

For external users, roles come from group mappings. A GroupMapping ties an external directory group (scoped to its provider) to either a default role or a scoped role:

POST /api/group-mappings/
{
  "external_group": "net-eng-admins",
  "provider": "ldap",
  "default_role": 4          // → Network Admin
}

At each successful login, the role engine runs:

  • It refreshes the user's recorded group membership and auth source.
  • For external users, it matches the returned groups against the mappings for that provider. If several default-role mappings match, the highest level wins. If none match, the user falls back to Guest. Group-matched scoped roles are added, and stale ones from previous logins are removed.
  • For local users, the role is whatever an administrator set in the UI — the engine never overwrites it from groups.

This means access is re-evaluated every time an external user signs in, so revoking someone in your directory takes effect on their next login without any change inside Versus.


Assigning roles as an operator

Day-to-day access management happens under Access Control in the console, backed by these endpoints:

TaskEndpointWho
List the default rolesGET /api/default-roles/Any authenticated user
Create / edit scoped roles…/api/scoped-roles/Network Admin (≥4)
Assign a scoped role to a userPOST /api/role-assignments/Network Admin (≥4)
Map a directory group to a role…/api/group-mappings/Network Admin (≥4)
Configure an auth backend…/api/auth-backends/Super Admin (5)

Manual assignments are recorded with their assignment_source (manual vs. group_match) and who granted them, so the origin of every grant is auditable. To grant a scoped role to a specific user:

POST /api/role-assignments/
{ "user": 88, "scoped_role": 7 }

Users without sufficient access can request an elevation themselves — POST /api/users/request-role/ with operator or admin — which files a pending request and notifies administrators by email. An administrator approves or rejects it; the user's own token can never self-approve.


Where authorization sits in the platform

RBAC is one of two independent gates a request passes:

  1. Authentication & identity — every sign-in goes through the identity layer (SSO with mandatory MFA). Versus supports RFC 6238 TOTP as a second factor composed on top of whichever backend established the identity. See Platform Architecture.
  2. Authorization (RBAC) — the permission check described on this page. A denied action returns HTTP 403.

Distinct from both is license entitlement. On licensed deployments a separate middleware gates whole modules by what the deployment (on-prem) or tenant (SaaS) has paid for; a request for an unlicensed module returns HTTP 402, not 403. Entitlement answers "is this feature included in your plan," RBAC answers "are you allowed to do it" — the two are orthogonal, and both must pass.

In multi-tenant deployments, a Tenant Admin console lets a tenant administer users within its own organization only. The assignable roles there are exactly Viewer, Operator, and Tenant Admin — Super Admin is never grantable through it — and every operation is bound to the tenant ID carried in the caller's token, so no admin can reach into another tenant. Tenant isolation is additionally enforced with row-level security in the database as a defense-in-depth backstop beneath these application checks.


Design notes

  • Server-side, always. All authorization runs through centralized permission classes in the back end. Hiding a button in the UI is a convenience, not a control.
  • Union, not intersection. Scoped roles only add capability; they never subtract what a default role grants. Keep baselines low and grant reach deliberately.
  • Least privilege for automation. Give service accounts a scoped role holding exactly the permissions their pipeline needs, rather than an operator or admin default role. See Running Workflows via the API.
  • Directory-driven where possible. For external users, manage access by group membership in your IdP and let the role engine resolve it at login.

Related