Roles & permissions
WatchTower15 uses role-based access control (RBAC) scoped to each organisation. Permissions are granular and per-module; roles bundle permissions; users hold one or more roles. Everything is enforced server-side on every request, so the UI and the API share exactly one source of truth.
The model
Section titled “The model”- Organisation-scoped. Roles and assignments belong to an organisation. A role in one organisation has no effect in another — a user can be an admin in one org and read-only in another with no bleed-through.
- Permissions are the atoms. Each permission is a
module.tierstring. Tiers areview,edit(create + update), anddelete. - Roles bundle permissions. A role is a named set of permissions.
- Users can hold multiple roles. Effective access is the union of their roles’ permissions.
Built-in roles
Section titled “Built-in roles”Every organisation is seeded with two system roles that cannot be renamed or deleted:
| Role | Access |
|---|---|
| Admin | Full access. Enforcement grants admins everything via a fast super-user bypass, so admins are never blocked by a missing individual permission. |
| Regular Users | Read-only starter role: servers.view, server_profiles.view, domains.view, database.view, logs.view, services.view. Log sources, custom metrics, alarms and incidents are not included; an Admin can add their view permissions to this role, or grant them through a custom role. Without custom_metrics.view, a server’s page does not show the custom metrics linked to it. A server’s and a database’s own alarms and incidents are still readable on its page (see below). New members default to this role on invitation. |
The person who registers an organisation holds its Admin role, so the first member can invite everyone else and assign their roles. Registering another organisation with an existing account makes you its Admin too, and leaves your roles in your other organisations as they are.
You can create any number of custom roles — e.g. a “Domain manager” with the domain and DNS permissions, or an “On-call” role with incident and policy access — and assign several to a user as needed.
The permission catalogue
Section titled “The permission catalogue”WatchTower15 ships a catalogue of granular permissions across every functional module:
| Module | Permissions |
|---|---|
| Servers | servers.view · servers.edit · servers.delete |
| Server profiles | server_profiles.view · server_profiles.edit · server_profiles.delete |
| Domains | domains.view · domains.edit · domains.delete |
| Services | services.view · services.edit · services.delete · services.parameters |
| Logs | logs.view |
| Log sources | log_sources.view · log_sources.edit · log_sources.delete |
| Custom metrics & metric sources | custom_metrics.view · custom_metrics.edit · custom_metrics.delete |
| Databases | database.view · database.edit · database.delete |
| Incidents | incidents.view · incidents.edit · incidents.delete |
| Alarms | alarms.view · alarms.edit · alarms.delete |
| Alarm policies | policies.view · policies.edit · policies.delete |
| Notification channels | channels.view · channels.edit · channels.delete |
| Contact groups | contact_groups.view · contact_groups.edit · contact_groups.delete |
| Tags | tags.view · tags.edit · tags.delete |
| Users | users.view · users.edit · users.delete |
| Settings | settings.view · settings.edit |
| Billing | billing.view · billing.edit |
| Audit | audit.view |
| Security findings | security.view · security.edit |
| API access | api_access.view · api_access.edit |
edit covers both creating and updating; delete is separated so you can grant
change-without-destroy access — a common requirement for junior operators.
services.parameters separates changing a service’s check from deciding what the check may
read on your servers. It is needed, beside services.edit, to add a service with
parameters or with authentication other than None, and to change a
service’s parameters or authentication. A save that leaves them as they were (a kept password
or token included) needs only services.edit, so a member without services.parameters can
still create and edit services that read nothing. Admins have it; grant it to other roles
yourself.
security.view is needed for the package list behind a server’s OS updates card on the Info tab (the package, repository and reboot-package names are an attack map of the server); the counts on the card show with servers.view. security.view and security.edit are otherwise reserved for security findings, which WatchTower15 has not shipped yet. Admins hold them; the Regular Users role does not.
api_access.view lets a member create and hold API keys for the organisation, to call the API from scripts and tools; api_access.edit is for keys that may change things, which arrive with the API’s write operations. Admins hold both; the Regular Users role does not, so grant api_access.view to the roles whose members should have keys. A key only ever carries scopes its owner holds, and stops using one the moment the owner’s role loses it.
Some screens follow a permission too. A menu item shows only to members who can open its page, and a pasted link to a page you can’t open takes you to the Dashboard:
| Menu item | Needs |
|---|---|
| Servers | servers.view |
| Domains | domains.view |
| Databases | database.view |
| Logs | logs.view |
| Metrics | custom_metrics.view |
| Services | services.view |
| Incidents | incidents.view |
| Policies | policies.view |
| Channels | channels.view |
| Contact Groups | contact_groups.view |
| Settings | settings.view |
| Users and Roles | users.view |
| Audit | audit.view |
| Tags | tags.view |
| Billing | billing.view |
Dashboard needs none, so the default Regular Users role sees Dashboard, Servers, Domains, Databases, Logs and
Services. A link or button to a page you can’t open is hidden too: Manage policies → in a resource’s alarms needs
policies.view, the Servers page’s Profiles button server_profiles.view, and Add and Edit on Domains,
Services and Server Profiles their .edit permission. On a server’s page, the ⋯ menu’s actions and the edits
made in place — its name, its notes, and (change) on its Profile and Tags cards — need servers.edit, except
Delete, which needs servers.delete; changing its profile also needs server_profiles.view, and the ⋯ menu is
hidden when it has nothing you can use (Changing a server). The Tags filter on list pages needs tags.view, and is
hidden without it. On the Logs page, the Databases group of Sources needs database.view beside logs.view
(below). A dashboard widget’s
By tag picker needs only the view permission for its resource type, such as
domains.view for a domain widget.
Databases: database.view reads them, their tabs included (the
Logs tab and the Info tab’s Logs card among them),
database.edit adds them and changes their setup (including Test again, on the Collectors
tab, the Cloud metrics card and the Logs card, Reassign now, Pause, Resume and Accept new
key), and database.delete deletes them. A server’s Databases card, listing the databases it
collects or runs, needs both servers.view and database.view.
A database’s slow and error logs on the Logs page, chosen
as a source beside the log lines, need both logs.view and database.view. Without
database.view, Sources has no Databases group, a saved view or a shared link opens
without its databases, and the API answers 403 to a request naming one. database.view alone
does not open the Logs page: it reads each database’s own Logs tab.
Custom metrics shown on a server need both
servers.view and custom_metrics.view: the server’s Custom metrics tab and its Overview
card appear only to someone holding the two. On a metric’s or source’s page, the servers it is
shown on are named only with servers.view; without it, the page gives their number.
Organisation → Settings: settings.view shows the menu item,
its three tabs and every card, read-only. settings.edit adds each card’s Edit button and its
edit page, and Regenerate for the install token. Open in Audit Trail → on the Recent
settings changes card needs audit.view.
On Organisation → Users, the 2FA column and the Two-factor field on a member’s page
need users.view, as the page does. See Two-factor
authentication.
Admin-only actions
Section titled “Admin-only actions”A few actions act on the whole organisation, or on someone’s sign-in, and are for the Admin role alone: no custom role can grant them, whatever its permissions. Each asks you to confirm first.
| Action | Where | What it does |
|---|---|---|
| Sign out everyone | Organisation → Settings → Authentication, Sign out every member | Ends every member’s session in this organisation, yours included |
| Revoke all keys | Organisation → Settings → Authentication, API Keys | Revokes every live API key of the organisation |
| Expire every password now | Organisation → Settings → Authentication, Password Management | Every member who signs in with a password must choose a new one, you included |
| Reset two-factor | A member’s page under Organisation → Users | Turns off the member’s two-factor authentication and signs them out; refused when they also belong to another organisation |
See Organisation settings and Two-factor authentication.
The Audit tab and the audit trail
Section titled “The Audit tab and the audit trail”The Audit page and a resource’s Audit tab are one list: the tab is the page locked to that resource (Audit trail).
audit.viewopens the organisation’s Audit page — every event, with each request’s IP address, user agent and URL. On a resource’s Audit tab it adds the same: the IP Address column and, in an opened event, the user agent and URL, with the User filter and Open in Audit Trail →. Without it, the IP address, user agent and URL never reach your browser. It also adds the Audit and API tabs to a member’s page under Organisation → Users (A member’s Audit and API tabs).- A resource’s Audit tab has no permission of its own. It follows the resource’s
viewpermission —servers.view,database.view,domains.view,services.view,log_sources.view,server_profiles.view, orcustom_metrics.viewfor custom metrics and metric sources. Whoever can view the resource sees its whole Audit tab, including its incident and alarm events. Changes to the servers a custom metric or metric source is shown on are on that metric’s or source’s Audit tab. users.viewlinks each person’s name to their page, on the Audit page and on every Audit tab, and gives the tab its User filter. It opens a member’s page, with its Info and Permissions tabs: the member’s roles, each linked to its page, and every permission they grant together.- An incident event links to the incident’s page on the Audit page, for holders of
incidents.view. On an Audit tab it links the resource’s own incidents instead: a server’s or a database’s with its view permission alone, a domain’s, service’s, log source’s or custom metric’s withincidents.viewtoo. - Acting on those events needs its own permission. Acknowledging or resolving an
incident needs
incidents.edit, and changing an alarm needsalarms.edit.
A server’s alarms and incidents
Section titled “A server’s alarms and incidents”Anyone who can view a server — servers.view — reads its alarms and incidents on the
server’s page, without alarms.view or incidents.view: the alarm counts in the
header, and the Alarms and Incidents tabs, covering the server and its volumes,
listening ports and system services. They can evaluate the server as a whole, but not
act on it:
- Acknowledging or resolving an incident needs
incidents.edit. Adding or changing an alarm needsalarms.edit, and deleting onealarms.delete. - The Incidents menu item, its list of every incident in the organisation, and an
incident’s own page need
incidents.view, and so does seeing who was notified, and on which channel. Withoutincidents.view, an incident on the server’s page reads as text, with who acknowledged or resolved it.
A database’s alarms and incidents are readable the same way: anyone with database.view reads
the alarm counts in its header, its Alarms tab and its Incidents tab, without
alarms.view or incidents.view (see A database’s alarms and
A database’s incidents). Acting on them needs the same
permissions as on a server’s page. The alarms and incidents of a domain, service, log source or
custom metric need alarms.view and incidents.view. And the custom metrics
linked to a server are not the server’s own: its Custom metrics tab and card also need
custom_metrics.view.
Alarm policies need policies.view, everywhere. On every resource — a server, domain,
service, log source or custom metric, and a server profile’s alarm templates — someone without
policies.view sees how many policies notify an alarm, not which ones, and not who or what they
notify. On a resource’s Audit tab, a change to an alarm’s policies reads as a count, such as
+2 policies, unless you also hold audit.view. The Admin role sees everything.
How enforcement works
Section titled “How enforcement works”On every authenticated request, WatchTower15:
- Resolves the caller’s organisation context (the team the request targets).
- Grants immediately if the caller holds the Admin role.
- Otherwise checks whether any of the caller’s roles include the specific
permission the endpoint requires (e.g.
domains.editto update a domain). - Returns 403 Forbidden if not.
Because the check is per-endpoint and server-side, there’s no way to reach a protected action by calling the API directly — the browser and the API are held to the same permission.
Working with roles
Section titled “Working with roles”- Invite a member — they start as Regular Users (read-only).
- Assign roles — give them one or more roles; access is the union.
- Create custom roles — scope a role to exactly the modules a job needs.
- Delete guardrails — system roles can’t be removed, and a role still assigned to members can’t be deleted until it’s unassigned.
Related
Section titled “Related”- Audit trail — who did what, gated by
audit.view; each resource’s Audit tab follows itsviewpermission. - Single sign-on — how members authenticate.
- Organisation settings — what
settings.viewandsettings.editopen, and the Admin-only actions. - API —
api_access.viewand the keys it lets a member hold.