RBAC: Make RBAC action names more consistent (#49730) (#50083)

* update action names

* correctly retrieve teams for signed in user

* remove test

* undo swagger changes

* undo swagger changes pt2

* add migration from old action names to the new ones

* rename from list to read

* linting

* also update alertign actions

* fix migration

(cherry picked from commit 5dbea9996b)

Co-authored-by: Ieva <ieva.vasiljeva@grafana.com>
This commit is contained in:
Grot (@grafanabot)
2022-06-02 15:15:40 +02:00
committed by GitHub
co-authored by Ieva
parent b342fe6e30
commit 3e7a2111e6
32 changed files with 279 additions and 222 deletions
@@ -79,7 +79,7 @@ Query Parameters:
| Action | Scope |
| ---------- | -------- |
| roles:list | roles:\* |
| roles:read | roles:\* |
#### Example request
@@ -180,13 +180,13 @@ Content-Type: application/json; charset=UTF-8
"created": "2021-11-19T10:48:00+01:00"
},
{
"action": "reports.admin:create",
"action": "reports:create",
"scope": "",
"updated": "2021-11-19T10:48:00+01:00",
"created": "2021-11-19T10:48:00+01:00"
},
{
"action": "reports.admin:write",
"action": "reports:write",
"scope": "reports:*",
"updated": "2021-11-19T10:48:00+01:00",
"created": "2021-11-19T10:48:00+01:00"
@@ -489,7 +489,7 @@ Query Parameters:
| Action | Scope |
| ---------------- | -------------------- |
| users.roles:list | users:id:`<user ID>` |
| users.roles:read | users:id:`<user ID>` |
#### Example request
@@ -537,7 +537,7 @@ Lists the permissions that a given user has.
| Action | Scope |
| ---------------------- | -------------------- |
| users.permissions:list | users:id:`<user ID>` |
| users.permissions:read | users:id:`<user ID>` |
#### Example request
@@ -763,7 +763,7 @@ Query Parameters:
| Action | Scope |
| ---------------- | -------------------- |
| teams.roles:list | teams:id:`<team ID>` |
| teams.roles:read | teams:id:`<team ID>` |
#### Example request
+10 -10
View File
@@ -380,9 +380,9 @@ Change password for a specific user.
See note in the [introduction]({{< ref "#admin-api" >}}) for an explanation.
| Action | Scope |
| --------------------- | --------------- |
| users.password:update | global.users:\* |
| Action | Scope |
| -------------------- | --------------- |
| users.password:write | global.users:\* |
**Example Request**:
@@ -413,9 +413,9 @@ Only works with Basic Authentication (username and password). See [introduction]
See note in the [introduction]({{< ref "#admin-api" >}}) for an explanation.
| Action | Scope |
| ------------------------ | --------------- |
| users.permissions:update | global.users:\* |
| Action | Scope |
| ----------------------- | --------------- |
| users.permissions:write | global.users:\* |
**Example Request**:
@@ -516,7 +516,7 @@ See note in the [introduction]({{< ref "#admin-api" >}}) for an explanation.
| Action | Scope |
| -------------------- | --------------- |
| users.authtoken:list | global.users:\* |
| users.authtoken:read | global.users:\* |
**Example Request**:
@@ -573,9 +573,9 @@ Only works with Basic Authentication (username and password). See [introduction]
See note in the [introduction]({{< ref "#admin-api" >}}) for an explanation.
| Action | Scope |
| ---------------------- | --------------- |
| users.authtoken:update | global.users:\* |
| Action | Scope |
| --------------------- | --------------- |
| users.authtoken:write | global.users:\* |
**Example Request**:
@@ -71,9 +71,9 @@ Manually ask license issuer for a new token.
See note in the [introduction]({{< ref "#enterprise-license-api" >}}) for an explanation.
| Action | Scope |
| ---------------- | ----- |
| licensing:update | n/a |
| Action | Scope |
| --------------- | ----- |
| licensing:write | n/a |
### Examples
+6 -6
View File
@@ -149,9 +149,9 @@ Content-Type: application/json
See note in the [introduction]({{< ref "#organization-api" >}}) for an explanation.
| Action | Scope |
| --------------------- | -------- |
| org.users.role:update | users:\* |
| Action | Scope |
| --------------- | -------- |
| org.users:write | users:\* |
**Example Request**:
@@ -605,9 +605,9 @@ Only works with Basic Authentication (username and password), see [introduction]
See note in the [introduction]({{< ref "#organization-api" >}}) for an explanation.
| Action | Scope |
| --------------------- | -------- |
| org.users.role:update | users:\* |
| Action | Scope |
| --------------- | -------- |
| org.users:write | users:\* |
**Example Request**:
+13 -12
View File
@@ -140,9 +140,9 @@ Content-Type: application/json
See note in the [introduction]({{< ref "#user-api" >}}) for an explanation.
| Action | Scope |
| ---------- | -------- |
| users:read | users:\* |
| Action | Scope |
| ---------- | --------------- |
| users:read | global.users:\* |
**Example Request**:
@@ -241,9 +241,9 @@ Content-Type: application/json
See note in the [introduction]({{< ref "#user-api" >}}) for an explanation.
| Action | Scope |
| ----------- | -------- |
| users:write | users:\* |
| Action | Scope |
| ----------- | --------------- |
| users:write | global.users:\* |
**Example Request**:
@@ -280,9 +280,9 @@ Content-Type: application/json
See note in the [introduction]({{< ref "#user-api" >}}) for an explanation.
| Action | Scope |
| ---------- | -------- |
| users:read | users:\* |
| Action | Scope |
| ---------- | --------------- |
| users:read | global.users:\* |
**Example Request**:
@@ -318,9 +318,10 @@ Content-Type: application/json
See note in the [introduction]({{< ref "#user-api" >}}) for an explanation.
| Action | Scope |
| ---------------- | -------- |
| users.teams:read | users:\* |
| Action | Scope |
| ---------- | --------------- |
| users:read | global.users:\* |
| teams:read | teams:\* |
**Example Request**:
@@ -91,9 +91,9 @@ To learn more about the permissions you can grant for each resource, refer to [R
If you are a Grafana Enterprise customer, you can create custom roles to manage user permissions in a way that meets your security requirements.
Custom roles contain unique combinations of permissions _actions_ and _scopes_. An action defines the action a use can perform on a Grafana resource. For example, the `teams.roles:list` action allows a user to see a list of roles associated with each team.
Custom roles contain unique combinations of permissions _actions_ and _scopes_. An action defines the action a use can perform on a Grafana resource. For example, the `teams.roles:read` action allows a user to see a list of roles associated with each team.
A scope describes where an action can be performed. For example, the `teams:id:1` scope restricts the user's action to the team with ID `1`. When paired with the `teams.roles:list` action, this permission prohibits the user from viewing the roles for teams other than team `1`.
A scope describes where an action can be performed. For example, the `teams:id:1` scope restricts the user's action to the team with ID `1`. When paired with the `teams.roles:read` action, this permission prohibits the user from viewing the roles for teams other than team `1`.
Consider creating a custom role when fixed roles do not meet your permissions requirements.
@@ -27,7 +27,7 @@ The following list contains role-based access control actions.
| `alert.instances.external:write` | `datasources:*`<br>`datasources:uid:*` | Manage alerts and silences in data sources that support alerting. |
| `alert.instances:create` | n/a | Create silences in the current organization. |
| `alert.instances:read` | n/a | Read alerts and silences in the current organization. |
| `alert.instances:update` | n/a | Update and expire silences in the current organization. |
| `alert.instances:write` | n/a | Update and expire silences in the current organization. |
| `alert.notifications.external:read` | `datasources:*`<br>`datasources:uid:*` | Read templates, contact points, notification policies, and mute timings in data sources that support alerting. |
| `alert.notifications.external:write` | `datasources:*`<br>`datasources:uid:*` | Manage templates, contact points, notification policies, and mute timings in data sources that support alerting. |
| `alert.notifications:write` | n/a | Manage templates, contact points, notification policies, and mute timings in the current organization. |
@@ -37,7 +37,7 @@ The following list contains role-based access control actions.
| `alert.rules:create` | `folders:*`<br>`folders:uid:*` | Create Grafana alert rules in a folder. Combine this permission with `folders:read` in a scope that includes the folder and `datasources:query` in the scope of data sources the user can query. |
| `alert.rules:delete` | `folders:*`<br>`folders:uid:*` | Delete Grafana alert rules in a folder. Combine this permission with `folders:read` in a scope that includes the folder and `datasources:query` in the scope of data sources the user can query. |
| `alert.rules:read` | `folders:*`<br>`folders:uid:*` | Read Grafana alert rules in a folder. Combine this permission with `folders:read` in a scope that includes the folder and `datasources:query` in the scope of data sources the user can query. |
| `alert.rules:update` | `folders:*`<br>`folders:uid:*` | Update Grafana alert rules in a folder. Combine this permission with `folders:read` in a scope that includes the folder and `datasources:query` in the scope of data sources the user can query. |
| `alert.rules:write` | `folders:*`<br>`folders:uid:*` | Update Grafana alert rules in a folder. Combine this permission with `folders:read` in a scope that includes the folder and `datasources:query` in the scope of data sources the user can query. |
| `annotations:create` | `annotations:*`<br>`annotations:type:*` | Create annotations. |
| `annotations:delete` | `annotations:*`<br>`annotations:type:*` | Delete annotations. |
| `annotations:read` | `annotations:*`<br>`annotations:type:*` | Read annotations and annotation tags. |
@@ -73,8 +73,8 @@ The following list contains role-based access control actions.
| `licensing.reports:read` | n/a | Get custom permission reports. |
| `licensing:delete` | n/a | Delete the license token. |
| `licensing:read` | n/a | Read licensing information. |
| `licensing:update` | n/a | Update the license token. |
| `org.users.role:update` | `users:*` <br> `users:id:*` | Update the organization role (`Viewer`, `Editor`, or `Admin`) of an organization. |
| `licensing:write` | n/a | Update the license token. |
| `org.users:write` | `users:*` <br> `users:id:*` | Update the organization role (`Viewer`, `Editor`, or `Admin`) of a user. |
| `org.users:add` | `users:*` | Add a user to an organization. |
| `org.users:read` | `users:*` <br> `users:id:*` | Get user profiles within an organization. |
| `org.users:remove` | `users:*` <br> `users:id:*` | Remove a user from an organization. |
@@ -87,16 +87,15 @@ The following list contains role-based access control actions.
| `orgs:read` | `orgs:*` <br> `orgs:id:*` | Read one or more organizations. |
| `orgs:write` | `orgs:*` <br> `orgs:id:*` | Update one or more organizations. |
| `provisioning:reload` | `provisioners:*` | Reload provisioning files. To find the exact scope for specific provisioner, see [Scope definitions]({{< relref "#scope-definitions" >}}). |
| `reports.admin:create` | n/a | Create reports. |
| `reports.admin:write` | `reports:*` <br> `reports:id:*` | Update reports. |
| `reports:create` | n/a | Create reports. |
| `reports:write` | `reports:*` <br> `reports:id:*` | Update reports. |
| `reports.settings:read` | n/a | Read report settings. |
| `reports.settings:write` | n/a | Update report settings. |
| `reports:delete` | `reports:*` <br> `reports:id:*` | Delete reports. |
| `reports:read` | `reports:*` | List all available reports or get a specific report. |
| `reports:send` | `reports:*` | Send a report email. |
| `roles:delete` | `permissions:type:delegate` | Delete a custom role. |
| `roles:list` | `roles:*` | List available roles without permissions. |
| `roles:read` | `roles:*` <br> `roles:uid:*` | Read a specific role with its permissions. |
| `roles:read` | `roles:*` <br> `roles:uid:*` | List roles and read a specific with its permissions. |
| `roles:write` | `permissions:type:delegate` | Create or update a custom role. |
| `roles:write` | `permissions:type:escalate` | Reset basic roles to their default permissions. |
| `server.stats:read` | n/a | Read Grafana instance statistics. |
@@ -106,23 +105,22 @@ The following list contains role-based access control actions.
| `teams.permissions:read` | `teams:*`<br>`teams:id:*` | Read members and External Group Synchronization setup for teams. |
| `teams.permissions:write` | `teams:*`<br>`teams:id:*` | Add, remove and update members and manage External Group Synchronization setup for teams. |
| `teams.roles:add` | `permissions:type:delegate` | Assign a role to a team. |
| `teams.roles:list` | `teams:*` | List roles assigned directly to a team. |
| `teams.roles:read` | `teams:*` | List roles assigned directly to a team. |
| `teams.roles:remove` | `permissions:type:delegate` | Unassign a role from a team. |
| `teams:create` | n/a | Create teams. |
| `teams:delete` | `teams:*`<br>`teams:id:*` | Delete one or more teams. |
| `teams:read` | `teams:*`<br>`teams:id:*` | Read one or more teams and team preferences. |
| `teams:write` | `teams:*`<br>`teams:id:*` | Update one or more teams and team preferences. |
| `users.authtoken:list` | `global.users:*` <br> `global.users:id:*` | List authentication tokens that are assigned to a user. |
| `users.authtoken:update` | `global.users:*` <br> `global.users:id:*` | Update authentication tokens that are assigned to a user. |
| `users.password:update` | `global.users:*` <br> `global.users:id:*` | Update a user’s password. |
| `users.permissions:list` | `users:*` | List permissions of a user. |
| `users.permissions:update` | `global.users:*` <br> `global.users:id:*` | Update a user’s organization-level permissions. |
| `users.quotas:list` | `global.users:*` <br> `global.users:id:*` | List a user’s quotas. |
| `users.quotas:update` | `global.users:*` <br> `global.users:id:*` | Update a user’s quotas. |
| `users.authtoken:read` | `global.users:*` <br> `global.users:id:*` | List authentication tokens that are assigned to a user. |
| `users.authtoken:write` | `global.users:*` <br> `global.users:id:*` | Update authentication tokens that are assigned to a user. |
| `users.password:write` | `global.users:*` <br> `global.users:id:*` | Update a user’s password. |
| `users.permissions:read` | `users:*` | List permissions of a user. |
| `users.permissions:write` | `global.users:*` <br> `global.users:id:*` | Update a user’s organization-level permissions. |
| `users.quotas:read` | `global.users:*` <br> `global.users:id:*` | List a user’s quotas. |
| `users.quotas:write` | `global.users:*` <br> `global.users:id:*` | Update a user’s quotas. |
| `users.roles:add` | `permissions:type:delegate` | Assign a role to a user. |
| `users.roles:list` | `users:*` | List roles assigned directly to a user. |
| `users.roles:read` | `users:*` | List roles assigned directly to a user. |
| `users.roles:remove` | `permissions:type:delegate` | Unassign a role from a user. |
| `users.teams:read` | `global.users:*` <br> `global.users:id:*` | Read a user’s teams. |
| `users:create` | n/a | Create a user. |
| `users:delete` | `global.users:*` <br> `global.users:id:*` | Delete a user. |
| `users:disable` | `global.users:*` <br> `global.users:id:*` | Disable a user. |
@@ -65,7 +65,7 @@ curl --location --request GET '<grafana_url>/api/access-control/roles/qQui_LCMk'
"created": "2021-05-17T20:49:18+02:00"
},
{
"action": "org.users.role:update",
"action": "org.users:write",
"scope": "users:*",
"updated": "2021-05-17T20:49:18+02:00",
"created": "2021-05-17T20:49:18+02:00"
@@ -178,7 +178,7 @@ roles:
- name: 'fixed:org.users:writer'
global: true
permissions:
- action: 'org.users.role:update'
- action: 'org.users:write'
scope: 'users:*'
state: 'absent'
- action: 'org.users:add'
@@ -283,7 +283,7 @@ roles:
global: true
permissions:
# Permissions to remove
- action: 'teams.roles:list'
- action: 'teams.roles:read'
scope: 'teams:*'
state: 'absent'
- action: 'teams.roles:remove'
@@ -173,7 +173,6 @@ roles:
| action | scope |
| -------------- | --------------------------- |
| `roles:list` | `roles:*` |
| `roles:read` | `roles:*` |
| `roles:write` | `permissions:type:delegate` |
| `roles:delete` | `permissions:type:delegate` |
@@ -204,12 +203,12 @@ roles:
- Add the following permissions to the `basic:viewer` role, using provisioning or the [RBAC HTTP API]({{< relref "../../developers/http_api/access_control.md#update-a-role" >}}):
| Action | Scope |
| ---------------------- | ------------------------------- |
| `reports.admin:create` | n/a |
| `reports.admin:write` | `reports:*` <br> `reports:id:*` |
| `reports:read` | `reports:*` |
| `reports:send` | `reports:*` |
| Action | Scope |
| ---------------- | ------------------------------- |
| `reports:create` | n/a |
| `reports:write` | `reports:*` <br> `reports:id:*` |
| `reports:read` | `reports:*` |
| `reports:send` | `reports:*` |
### Prevent a Grafana Admin from creating and inviting users
@@ -24,59 +24,59 @@ The following tables list permissions associated with basic and fixed roles.
## Fixed role definitions
| Fixed role | Permissions | Description |
| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `fixed:alerting.instances:editor` | All permissions from `fixed:alerting.instances:reader` and<br> `alert.instances:create`<br>`alert.instances:update` for organization scope <br> `alert.instances.external:write` for scope `datasources:*` | Create, update and expire all silences in the organization produced by Grafana, Mimir, and Loki.[\*](#alerting-roles) |
| `fixed:alerting.instances:reader` | `alert.instances:read` for organization scope <br> `alert.instances.external:read` for scope `datasources:*` | Read all alerts and silences in the organization produced by Grafana Alerts and Mimir and Loki alerts and silences.[\*](#alerting-roles) |
| `fixed:alerting.notifications:editor` | All permissions from `fixed:alerting.notifications:reader` and<br>`alert.notifications:write`for organization scope<br>`alert.notifications.external:read` for scope `datasources:*` | Create, update, and delete contact points, templates, mute timings and notification policies for Grafana and external Alertmanager.[\*](#alerting-roles) |
| `fixed:alerting.notifications:reader` | `alert.notifications:read` for organization scope<br>`alert.notifications.external:read` for scope `datasources:*` | Read all Grafana and Alertmanager contact points, templates, and notification policies.[\*](#alerting-roles) |
| `fixed:alerting.rules:editor` | All permissions from `fixed:alerting.rules:reader` and <br> `alert.rule:create` <br> `alert.rule:update` <br> `alert.rule:delete` for scope `folders:*` <br> `alert.rules.external:write` for scope `datasources:*` | Create, update, and delete all\* Grafana, Mimir, and Loki alert rules.[\*](#alerting-roles) |
| `fixed:alerting.rules:reader` | `alert.rule:read` for scope `folders:*` <br> `alert.rules.external:read` for scope `datasources:*` | Read all\* Grafana, Mimir, and Loki alert rules.[\*](#alerting-roles) |
| `fixed:alerting:editor` | All permissions from `fixed:alerting.rules:editor` <br>`fixed:alerting.instances:editor`<br>`fixed:alerting.notifications:editor` | Create, update, and delete Grafana, Mimir, Loki and Alertmanager alert rules\*, silences, contact points, templates, mute timings, and notification policies.[\*](#alerting-roles) |
| `fixed:alerting:reader` | All permissions from `fixed:alerting.rules:reader` <br>`fixed:alerting.instances:reader`<br>`fixed:alerting.notifications:reader` | Read-only permissions for all Grafana, Mimir, Loki and Alertmanager alert rules\*, alerts, contact points, and notification policies.[\*](#alerting-roles) |
| `fixed:annotations.dashboard:writer` | `annotations:write` <br>`annotations.create`<br> `annotations:delete` for scope `annotations:type:dashboard` | Create, update and delete dashboard annotations and annotation tags. |
| `fixed:annotations:reader` | `annotations:read` for scopes `annotations:type:*` | Read all annotations and annotation tags. |
| `fixed:annotations:writer` | All permissions from `fixed:annotations:reader` <br>`annotations:write` <br>`annotations.create`<br> `annotations:delete` for scope `annotations:type:*` | Read, create, update and delete all annotations and annotation tags. |
| `fixed:apikeys:reader` | `apikeys:read` for scope `apikeys:*` | Read all api keys. |
| `fixed:apikeys:writer` | All permissions from `fixed:apikeys:reader` and <br> `apikeys:create` <br> `apikeys:delete` for scope `apikeys:*` | Read, create, delete all api keys. |
| `fixed:dashboards.permissions:reader` | `dashboards.permissions:read` | Read all dashboard permissions. |
| `fixed:dashboards.permissions:writer` | All permissions from `fixed:dashboards.permissions:reader` and <br>`dashboards.permissions:write` | Read and update all dashboard permissions. |
| `fixed:dashboards:creator` | `dashboards:create`<br>`folders:read` | Create dashboards. |
| `fixed:dashboards:reader` | `dashboards:read` | Read all dashboards. |
| `fixed:dashboards:writer` | All permissions from `fixed:dashboards:reader` and <br>`dashboards:write`<br>`dashboards:edit`<br>`dashboards:delete`<br>`dashboards:create`<br>`dashboards.permissions:read`<br>`dashboards.permissions:write` | Read, create, update, and delete all dashboards. |
| `fixed:datasources.permissions:reader` | `datasources.permissions:read` | Read data source permissions. |
| `fixed:datasources.permissions:writer` | All permissions from `fixed:datasources.permissions:reader` and <br>`datasources.permissions:write` | Create, read, or delete permissions of a data source. |
| `fixed:datasources:explorer` | `datasources:explore` | Enable the Explore feature. Data source permissions still apply, you can only query data sources for which you have query permissions. |
| `fixed:datasources:id:reader` | `datasources.id:read` | Read the ID of a data source based on its name. |
| `fixed:datasources:reader` | `datasources:read`<br>`datasources:query` | Read and query data sources. |
| `fixed:datasources:writer` | All permissions from `fixed:datasources:reader` and <br>`datasources:create`<br>`datasources:write`<br>`datasources:delete` | Read, query, create, delete, or update a data source. |
| `fixed:folders.permissions:reader` | `folders.permissions:read` | Read all folder permissions. |
| `fixed:folders.permissions:writer` | All permissions from `fixed:folders.permissions:reader` and <br>`folders.permissions:write` | Read and update all folder permissions. |
| `fixed:folders:creator` | `folders:create` | Create folders. |
| `fixed:folders:reader` | `folders:read`<br>`dashboards:read` | Read all folders and dashboards. |
| `fixed:folders:writer` | All permissions from `fixed:dashboards:writer` and <br>`folders:read`<br>`folders:write`<br>`folders:create`<br>`folders:delete`<br>`folders.permissions:read`<br>`folders.permissions:write` | Read, create, update, and delete all folders and dashboards. |
| `fixed:ldap:reader` | `ldap.user:read`<br>`ldap.status:read` | Read the LDAP configuration and LDAP status information. |
| `fixed:ldap:writer` | All permissions from `fixed:ldap:reader` and <br>`ldap.user:sync`<br>`ldap.config:reload` | Read and update the LDAP configuration, and read LDAP status information. |
| `fixed:licensing:reader` | `licensing:read`<br>`licensing.reports:read` | Read licensing information and licensing reports. |
| `fixed:licensing:writer` | All permissions from `fixed:licensing:viewer` and <br>`licensing:update`<br>`licensing:delete` | Read licensing information and licensing reports, update and delete the license token. |
| `fixed:org.users:reader` | `org.users:read` | Read users within a single organization. |
| `fixed:org.users:writer` | All permissions from `fixed:org.users:reader` and <br>`org.users:add`<br>`org.users:remove`<br>`org.users.role:update` | Within a single organization, add a user, invite a user, read information about a user and their role, remove a user from that organization, or change the role of a user. |
| `fixed:organization:maintainer` | All permissions from `fixed:organization:reader` and <br> `orgs:write`<br>`orgs:create`<br>`orgs:delete`<br>`orgs.quotas:write` | Create, read, write, or delete an organization. Read or write its quotas. This role needs to be assigned globally. |
| `fixed:organization:reader` | `orgs:read`<br>`orgs.quotas:read` | Read an organization and its quotas. |
| `fixed:organization:writer` | All permissions from `fixed:organization:reader` and <br> `orgs:write`<br>`orgs.preferences:read`<br>`orgs.preferences:write` | Read an organization, its quotas, or its preferences. Update organization properties, or its preferences. |
| `fixed:provisioning:writer` | `provisioning:reload` | Reload provisioning. |
| `fixed:reports:reader` | `reports:read`<br>`reports:send`<br>`reports.settings:read` | Read all reports and shared report settings. |
| `fixed:reports:writer` | All permissions from `fixed:reports:reader` and <br>`reports.admin:write`<br>`reports:delete`<br>`reports.settings:write` | Create, read, update, or delete all reports and shared report settings. |
| `fixed:roles:reader` | `roles:read`<br>`roles:list`<br>`teams.roles:list`<br>`users.roles:list`<br>`users.permissions:list` | Read all access control roles, roles and permissions assigned to users, teams. |
| `fixed:roles:writer` | All permissions from `fixed:roles:reader` and <br>`roles:write`<br>`roles:delete`<br>`teams.roles:add`<br>`teams.roles:remove`<br>`users.roles:add`<br>`users.roles:remove` | Create, read, update, or delete all roles, assign or unassign roles to users, teams. |
| `fixed:roles:resetter` | `roles:write` with scope `permissions:type:escalate` | Reset basic roles to their default. |
| `fixed:settings:reader` | `settings:read` | Read Grafana instance settings. |
| `fixed:settings:writer` | All permissions from `fixed:settings:reader` and<br>`settings:write` | Read and update Grafana instance settings. |
| `fixed:stats:reader` | `server.stats:read` | Read Grafana instance statistics. |
| `fixed:teams:creator` | `teams:create`<br>`org.users:read` | Create a team and list organization users (required to manage the created team). |
| `fixed:teams:writer` | `teams:create`<br>`teams:delete`<br>`teams:read`<br>`teams:write`<br>`teams.permissions:read`<br>`teams.permissions:write` | Create, read, update and delete teams and manage team memberships. |
| `fixed:users:reader` | `users:read`<br>`users.quotas:list`<br>`users.authtoken:list`<br>`users.teams:read` | Read all users and their information, such as team memberships, authentication tokens, and quotas. |
| `fixed:users:writer` | All permissions from `fixed:users:reader` and <br>`users:write`<br>`users:create`<br>`users:delete`<br>`users:enable`<br>`users:disable`<br>`users.password:update`<br>`users.permissions:update`<br>`users:logout`<br>`users.authtoken:update`<br>`users.quotas:update` | Read and update all attributes and settings for all users in Grafana: update user information, read user information, create or enable or disable a user, make a user a Grafana administrator, sign out a user, update a user’s authentication token, or update quotas for all users. |
| Fixed role | Permissions | Description |
| -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `fixed:alerting.instances:editor` | All permissions from `fixed:alerting.instances:reader` and<br> `alert.instances:create`<br>`alert.instances:write` for organization scope <br> `alert.instances.external:write` for scope `datasources:*` | Create, update and expire all silences in the organization produced by Grafana, Mimir, and Loki.[\*](#alerting-roles) |
| `fixed:alerting.instances:reader` | `alert.instances:read` for organization scope <br> `alert.instances.external:read` for scope `datasources:*` | Read all alerts and silences in the organization produced by Grafana Alerts and Mimir and Loki alerts and silences.[\*](#alerting-roles) |
| `fixed:alerting.notifications:editor` | All permissions from `fixed:alerting.notifications:reader` and<br>`alert.notifications:write`for organization scope<br>`alert.notifications.external:read` for scope `datasources:*` | Create, update, and delete contact points, templates, mute timings and notification policies for Grafana and external Alertmanager.[\*](#alerting-roles) |
| `fixed:alerting.notifications:reader` | `alert.notifications:read` for organization scope<br>`alert.notifications.external:read` for scope `datasources:*` | Read all Grafana and Alertmanager contact points, templates, and notification policies.[\*](#alerting-roles) |
| `fixed:alerting.rules:editor` | All permissions from `fixed:alerting.rules:reader` and <br> `alert.rule:create` <br> `alert.rule:update` <br> `alert.rule:delete` for scope `folders:*` <br> `alert.rules.external:write` for scope `datasources:*` | Create, update, and delete all\* Grafana, Mimir, and Loki alert rules.[\*](#alerting-roles) |
| `fixed:alerting.rules:reader` | `alert.rule:read` for scope `folders:*` <br> `alert.rules.external:read` for scope `datasources:*` | Read all\* Grafana, Mimir, and Loki alert rules.[\*](#alerting-roles) |
| `fixed:alerting:editor` | All permissions from `fixed:alerting.rules:editor` <br>`fixed:alerting.instances:editor`<br>`fixed:alerting.notifications:editor` | Create, update, and delete Grafana, Mimir, Loki and Alertmanager alert rules\*, silences, contact points, templates, mute timings, and notification policies.[\*](#alerting-roles) |
| `fixed:alerting:reader` | All permissions from `fixed:alerting.rules:reader` <br>`fixed:alerting.instances:reader`<br>`fixed:alerting.notifications:reader` | Read-only permissions for all Grafana, Mimir, Loki and Alertmanager alert rules\*, alerts, contact points, and notification policies.[\*](#alerting-roles) |
| `fixed:annotations.dashboard:writer` | `annotations:write` <br>`annotations.create`<br> `annotations:delete` for scope `annotations:type:dashboard` | Create, update and delete dashboard annotations and annotation tags. |
| `fixed:annotations:reader` | `annotations:read` for scopes `annotations:type:*` | Read all annotations and annotation tags. |
| `fixed:annotations:writer` | All permissions from `fixed:annotations:reader` <br>`annotations:write` <br>`annotations.create`<br> `annotations:delete` for scope `annotations:type:*` | Read, create, update and delete all annotations and annotation tags. |
| `fixed:apikeys:reader` | `apikeys:read` for scope `apikeys:*` | Read all api keys. |
| `fixed:apikeys:writer` | All permissions from `fixed:apikeys:reader` and <br> `apikeys:create` <br> `apikeys:delete` for scope `apikeys:*` | Read, create, delete all api keys. |
| `fixed:dashboards.permissions:reader` | `dashboards.permissions:read` | Read all dashboard permissions. |
| `fixed:dashboards.permissions:writer` | All permissions from `fixed:dashboards.permissions:reader` and <br>`dashboards.permissions:write` | Read and update all dashboard permissions. |
| `fixed:dashboards:creator` | `dashboards:create`<br>`folders:read` | Create dashboards. |
| `fixed:dashboards:reader` | `dashboards:read` | Read all dashboards. |
| `fixed:dashboards:writer` | All permissions from `fixed:dashboards:reader` and <br>`dashboards:write`<br>`dashboards:edit`<br>`dashboards:delete`<br>`dashboards:create`<br>`dashboards.permissions:read`<br>`dashboards.permissions:write` | Read, create, update, and delete all dashboards. |
| `fixed:datasources.permissions:reader` | `datasources.permissions:read` | Read data source permissions. |
| `fixed:datasources.permissions:writer` | All permissions from `fixed:datasources.permissions:reader` and <br>`datasources.permissions:write` | Create, read, or delete permissions of a data source. |
| `fixed:datasources:explorer` | `datasources:explore` | Enable the Explore feature. Data source permissions still apply, you can only query data sources for which you have query permissions. |
| `fixed:datasources:id:reader` | `datasources.id:read` | Read the ID of a data source based on its name. |
| `fixed:datasources:reader` | `datasources:read`<br>`datasources:query` | Read and query data sources. |
| `fixed:datasources:writer` | All permissions from `fixed:datasources:reader` and <br>`datasources:create`<br>`datasources:write`<br>`datasources:delete` | Read, query, create, delete, or update a data source. |
| `fixed:folders.permissions:reader` | `folders.permissions:read` | Read all folder permissions. |
| `fixed:folders.permissions:writer` | All permissions from `fixed:folders.permissions:reader` and <br>`folders.permissions:write` | Read and update all folder permissions. |
| `fixed:folders:creator` | `folders:create` | Create folders. |
| `fixed:folders:reader` | `folders:read`<br>`dashboards:read` | Read all folders and dashboards. |
| `fixed:folders:writer` | All permissions from `fixed:dashboards:writer` and <br>`folders:read`<br>`folders:write`<br>`folders:create`<br>`folders:delete`<br>`folders.permissions:read`<br>`folders.permissions:write` | Read, create, update, and delete all folders and dashboards. |
| `fixed:ldap:reader` | `ldap.user:read`<br>`ldap.status:read` | Read the LDAP configuration and LDAP status information. |
| `fixed:ldap:writer` | All permissions from `fixed:ldap:reader` and <br>`ldap.user:sync`<br>`ldap.config:reload` | Read and update the LDAP configuration, and read LDAP status information. |
| `fixed:licensing:reader` | `licensing:read`<br>`licensing.reports:read` | Read licensing information and licensing reports. |
| `fixed:licensing:writer` | All permissions from `fixed:licensing:viewer` and <br>`licensing:write`<br>`licensing:delete` | Read licensing information and licensing reports, update and delete the license token. |
| `fixed:org.users:reader` | `org.users:read` | Read users within a single organization. |
| `fixed:org.users:writer` | All permissions from `fixed:org.users:reader` and <br>`org.users:add`<br>`org.users:remove`<br>`org.users:write` | Within a single organization, add a user, invite a user, read information about a user and their role, remove a user from that organization, or change the role of a user. |
| `fixed:organization:maintainer` | All permissions from `fixed:organization:reader` and <br> `orgs:write`<br>`orgs:create`<br>`orgs:delete`<br>`orgs.quotas:write` | Create, read, write, or delete an organization. Read or write its quotas. This role needs to be assigned globally. |
| `fixed:organization:reader` | `orgs:read`<br>`orgs.quotas:read` | Read an organization and its quotas. |
| `fixed:organization:writer` | All permissions from `fixed:organization:reader` and <br> `orgs:write`<br>`orgs.preferences:read`<br>`orgs.preferences:write` | Read an organization, its quotas, or its preferences. Update organization properties, or its preferences. |
| `fixed:provisioning:writer` | `provisioning:reload` | Reload provisioning. |
| `fixed:reports:reader` | `reports:read`<br>`reports:send`<br>`reports.settings:read` | Read all reports and shared report settings. |
| `fixed:reports:writer` | All permissions from `fixed:reports:reader` and <br>`reports:create`<br>`reports:write`<br>`reports:delete`<br>`reports.settings:write` | Create, read, update, or delete all reports and shared report settings. |
| `fixed:roles:reader` | `roles:read`<br>`teams.roles:read`<br>`users.roles:read`<br>`users.permissions:read` | Read all access control roles, roles and permissions assigned to users, teams. |
| `fixed:roles:writer` | All permissions from `fixed:roles:reader` and <br>`roles:write`<br>`roles:delete`<br>`teams.roles:add`<br>`teams.roles:remove`<br>`users.roles:add`<br>`users.roles:remove` | Create, read, update, or delete all roles, assign or unassign roles to users, teams. |
| `fixed:roles:resetter` | `roles:write` with scope `permissions:type:escalate` | Reset basic roles to their default. |
| `fixed:settings:reader` | `settings:read` | Read Grafana instance settings. |
| `fixed:settings:writer` | All permissions from `fixed:settings:reader` and<br>`settings:write` | Read and update Grafana instance settings. |
| `fixed:stats:reader` | `server.stats:read` | Read Grafana instance statistics. |
| `fixed:teams:creator` | `teams:create`<br>`org.users:read` | Create a team and list organization users (required to manage the created team). |
| `fixed:teams:writer` | `teams:create`<br>`teams:delete`<br>`teams:read`<br>`teams:write`<br>`teams.permissions:read`<br>`teams.permissions:write` | Create, read, update and delete teams and manage team memberships. |
| `fixed:users:reader` | `users:read`<br>`users.quotas:read`<br>`users.authtoken:read`<br>` | Read all users and their information, such as team memberships, authentication tokens, and quotas. |
| `fixed:users:writer` | All permissions from `fixed:users:reader` and <br>`users:write`<br>`users:create`<br>`users:delete`<br>`users:enable`<br>`users:disable`<br>`users.password:write`<br>`users.permissions:write`<br>`users:logout`<br>`users.authtoken:write`<br>`users.quotas:write` | Read and update all attributes and settings for all users in Grafana: update user information, read user information, create or enable or disable a user, make a user a Grafana administrator, sign out a user, update a user’s authentication token, or update quotas for all users. |
### Alerting roles
+3 -3
View File
@@ -179,7 +179,7 @@ func (hs *HTTPServer) registerRoutes() {
usersRoute.Get("/", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersRead)), routing.Wrap(hs.searchUsersService.SearchUsers))
usersRoute.Get("/search", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersRead)), routing.Wrap(hs.searchUsersService.SearchUsersWithPaging))
usersRoute.Get("/:id", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersRead, userIDScope)), routing.Wrap(hs.GetUserByID))
usersRoute.Get("/:id/teams", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersTeamRead, userIDScope)), routing.Wrap(hs.GetUserTeams))
usersRoute.Get("/:id/teams", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersRead, userIDScope)), routing.Wrap(hs.GetUserTeams))
usersRoute.Get("/:id/orgs", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersRead, userIDScope)), routing.Wrap(hs.GetUserOrgList))
// query parameters /users/lookup?loginOrEmail=admin@example.com
usersRoute.Get("/lookup", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersRead, ac.ScopeGlobalUsersAll)), routing.Wrap(hs.GetUserByLoginOrEmail))
@@ -233,7 +233,7 @@ func (hs *HTTPServer) registerRoutes() {
orgRoute.Get("/users", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionOrgUsersRead)), routing.Wrap(hs.GetOrgUsersForCurrentOrg))
orgRoute.Get("/users/search", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionOrgUsersRead)), routing.Wrap(hs.SearchOrgUsersWithPaging))
orgRoute.Post("/users", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionOrgUsersAdd, ac.ScopeUsersAll)), quota("user"), routing.Wrap(hs.AddOrgUserToCurrentOrg))
orgRoute.Patch("/users/:userId", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionOrgUsersRoleUpdate, userIDScope)), routing.Wrap(hs.UpdateOrgUserForCurrentOrg))
orgRoute.Patch("/users/:userId", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionOrgUsersWrite, userIDScope)), routing.Wrap(hs.UpdateOrgUserForCurrentOrg))
orgRoute.Delete("/users/:userId", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionOrgUsersRemove, userIDScope)), routing.Wrap(hs.RemoveOrgUserForCurrentOrg))
// invites
@@ -279,7 +279,7 @@ func (hs *HTTPServer) registerRoutes() {
orgsRoute.Delete("/", authorizeInOrg(reqGrafanaAdmin, ac.UseOrgFromContextParams, ac.EvalPermission(ActionOrgsDelete)), routing.Wrap(hs.DeleteOrgByID))
orgsRoute.Get("/users", authorizeInOrg(reqGrafanaAdmin, ac.UseOrgFromContextParams, ac.EvalPermission(ac.ActionOrgUsersRead)), routing.Wrap(hs.GetOrgUsers))
orgsRoute.Post("/users", authorizeInOrg(reqGrafanaAdmin, ac.UseOrgFromContextParams, ac.EvalPermission(ac.ActionOrgUsersAdd, ac.ScopeUsersAll)), routing.Wrap(hs.AddOrgUser))
orgsRoute.Patch("/users/:userId", authorizeInOrg(reqGrafanaAdmin, ac.UseOrgFromContextParams, ac.EvalPermission(ac.ActionOrgUsersRoleUpdate, userIDScope)), routing.Wrap(hs.UpdateOrgUser))
orgsRoute.Patch("/users/:userId", authorizeInOrg(reqGrafanaAdmin, ac.UseOrgFromContextParams, ac.EvalPermission(ac.ActionOrgUsersWrite, userIDScope)), routing.Wrap(hs.UpdateOrgUser))
orgsRoute.Delete("/users/:userId", authorizeInOrg(reqGrafanaAdmin, ac.UseOrgFromContextParams, ac.EvalPermission(ac.ActionOrgUsersRemove, userIDScope)), routing.Wrap(hs.RemoveOrgUser))
orgsRoute.Get("/quotas", authorizeInOrg(reqGrafanaAdmin, ac.UseOrgFromContextParams, ac.EvalPermission(ActionOrgsQuotasRead)), routing.Wrap(hs.GetOrgQuotas))
orgsRoute.Put("/quotas/:target", authorizeInOrg(reqGrafanaAdmin, ac.UseOrgFromContextParams, ac.EvalPermission(ActionOrgsQuotasWrite)), routing.Wrap(hs.UpdateOrgQuota))
+4 -4
View File
@@ -325,10 +325,10 @@ func TestGetOrgUsersAPIEndpoint_AccessControlMetadata(t *testing.T) {
enableAccessControl: true,
expectedCode: http.StatusOK,
expectedMetadata: map[string]bool{
"org.users.role:update": true,
"org.users:add": true,
"org.users:read": true,
"org.users:remove": true},
"org.users:write": true,
"org.users:add": true,
"org.users:read": true,
"org.users:remove": true},
user: testServerAdminViewer,
targetOrg: testServerAdminViewer.OrgId,
},
+5 -5
View File
@@ -154,7 +154,7 @@ func (hs *HTTPServer) GetSignedInUserOrgList(c *models.ReqContext) response.Resp
// GET /api/user/teams
func (hs *HTTPServer) GetSignedInUserTeamList(c *models.ReqContext) response.Response {
return hs.getUserTeamList(c.Req.Context(), c.OrgId, c.UserId)
return hs.getUserTeamList(c, c.OrgId, c.UserId)
}
// GET /api/users/:id/teams
@@ -163,13 +163,13 @@ func (hs *HTTPServer) GetUserTeams(c *models.ReqContext) response.Response {
if err != nil {
return response.Error(http.StatusBadRequest, "id is invalid", err)
}
return hs.getUserTeamList(c.Req.Context(), c.OrgId, id)
return hs.getUserTeamList(c, c.OrgId, id)
}
func (hs *HTTPServer) getUserTeamList(ctx context.Context, orgID int64, userID int64) response.Response {
query := models.GetTeamsByUserQuery{OrgId: orgID, UserId: userID}
func (hs *HTTPServer) getUserTeamList(c *models.ReqContext, orgID int64, userID int64) response.Response {
query := models.GetTeamsByUserQuery{OrgId: orgID, UserId: userID, SignedInUser: c.SignedInUser}
if err := hs.SQLStore.GetTeamsByUser(ctx, &query); err != nil {
if err := hs.SQLStore.GetTeamsByUser(c.Req.Context(), &query); err != nil {
return response.Error(500, "Failed to get user teams", err)
}
+4 -3
View File
@@ -62,9 +62,10 @@ type GetTeamByIdQuery struct {
const FilterIgnoreUser int64 = 0
type GetTeamsByUserQuery struct {
OrgId int64
UserId int64 `json:"userId"`
Result []*TeamDTO `json:"teams"`
OrgId int64
UserId int64 `json:"userId"`
Result []*TeamDTO `json:"teams"`
SignedInUser *SignedInUser
}
type SearchTeamsQuery struct {
+1 -1
View File
@@ -11,7 +11,7 @@ import (
var sqlIDAcceptList = map[string]struct{}{
"id": {},
"org_user.user_id": {},
"role.id": {},
"role.uid": {},
"t.id": {},
"team.id": {},
"u.id": {},
+14 -15
View File
@@ -285,32 +285,31 @@ const (
ActionAPIKeyDelete = "apikeys:delete"
// Users actions
ActionUsersRead = "users:read"
ActionUsersWrite = "users:write"
ActionUsersTeamRead = "users.teams:read"
ActionUsersRead = "users:read"
ActionUsersWrite = "users:write"
// We can ignore gosec G101 since this does not contain any credentials.
// nolint:gosec
ActionUsersAuthTokenList = "users.authtoken:list"
ActionUsersAuthTokenList = "users.authtoken:read"
// We can ignore gosec G101 since this does not contain any credentials.
// nolint:gosec
ActionUsersAuthTokenUpdate = "users.authtoken:update"
ActionUsersAuthTokenUpdate = "users.authtoken:write"
// We can ignore gosec G101 since this does not contain any credentials.
// nolint:gosec
ActionUsersPasswordUpdate = "users.password:update"
ActionUsersPasswordUpdate = "users.password:write"
ActionUsersDelete = "users:delete"
ActionUsersCreate = "users:create"
ActionUsersEnable = "users:enable"
ActionUsersDisable = "users:disable"
ActionUsersPermissionsUpdate = "users.permissions:update"
ActionUsersPermissionsUpdate = "users.permissions:write"
ActionUsersLogout = "users:logout"
ActionUsersQuotasList = "users.quotas:list"
ActionUsersQuotasUpdate = "users.quotas:update"
ActionUsersQuotasList = "users.quotas:read"
ActionUsersQuotasUpdate = "users.quotas:write"
// Org actions
ActionOrgUsersRead = "org.users:read"
ActionOrgUsersAdd = "org.users:add"
ActionOrgUsersRemove = "org.users:remove"
ActionOrgUsersRoleUpdate = "org.users.role:update"
ActionOrgUsersRead = "org.users:read"
ActionOrgUsersAdd = "org.users:add"
ActionOrgUsersRemove = "org.users:remove"
ActionOrgUsersWrite = "org.users:write"
// LDAP actions
ActionLDAPUsersRead = "ldap.user:read"
@@ -363,12 +362,12 @@ const (
// Alerting rules actions
ActionAlertingRuleCreate = "alert.rules:create"
ActionAlertingRuleRead = "alert.rules:read"
ActionAlertingRuleUpdate = "alert.rules:update"
ActionAlertingRuleUpdate = "alert.rules:write"
ActionAlertingRuleDelete = "alert.rules:delete"
// Alerting instances (+silences) actions
ActionAlertingInstanceCreate = "alert.instances:create"
ActionAlertingInstanceUpdate = "alert.instances:update"
ActionAlertingInstanceUpdate = "alert.instances:write"
ActionAlertingInstanceRead = "alert.instances:read"
// Alerting Notification policies actions
+4 -8
View File
@@ -53,14 +53,14 @@ var (
DisplayName: "Organization user writer",
Description: "Within a single organization, add a user, invite a user, read information about a user and their role, remove a user from that organization, or change the role of a user.",
Group: "User administration (organizational)",
Version: 3,
Version: 4,
Permissions: ConcatPermissions(orgUsersReaderRole.Permissions, []Permission{
{
Action: ActionOrgUsersAdd,
Scope: ScopeUsersAll,
},
{
Action: ActionOrgUsersRoleUpdate,
Action: ActionOrgUsersWrite,
Scope: ScopeUsersAll,
},
{
@@ -116,16 +116,12 @@ var (
DisplayName: "User reader",
Description: "Read all users and their information, such as team memberships, authentication tokens, and quotas.",
Group: "User administration (global)",
Version: 4,
Version: 6,
Permissions: []Permission{
{
Action: ActionUsersRead,
Scope: ScopeGlobalUsersAll,
},
{
Action: ActionUsersTeamRead,
Scope: ScopeGlobalUsersAll,
},
{
Action: ActionUsersAuthTokenList,
Scope: ScopeGlobalUsersAll,
@@ -142,7 +138,7 @@ var (
DisplayName: "User writer",
Description: "Read and update all attributes and settings for all users in Grafana: update user information, read user information, create or enable or disable a user, make a user a Grafana administrator, sign out a user, update a user’s authentication token, or update quotas for all users.",
Group: "User administration (global)",
Version: 4,
Version: 5,
Permissions: ConcatPermissions(usersReaderRole.Permissions, []Permission{
{
Action: ActionUsersPasswordUpdate,
+1 -1
View File
@@ -270,7 +270,7 @@ func (g *dashboardGuardianImpl) getTeams() ([]*models.TeamDTO, error) {
return g.teams, nil
}
query := models.GetTeamsByUserQuery{OrgId: g.orgId, UserId: g.user.UserId}
query := models.GetTeamsByUserQuery{OrgId: g.orgId, UserId: g.user.UserId, SignedInUser: g.user}
err := g.store.GetTeamsByUser(g.ctx, &query)
g.teams = query.Result
+1 -1
View File
@@ -4,7 +4,7 @@ import "github.com/grafana/grafana/pkg/services/accesscontrol"
const (
ActionRead = "licensing:read"
ActionUpdate = "licensing:update"
ActionUpdate = "licensing:write"
ActionDelete = "licensing:delete"
ActionReportsRead = "licensing.reports:read"
)
+2 -2
View File
@@ -36,7 +36,7 @@ var (
DisplayName: "Rules Editor",
Description: "Can add, update, and delete rules in any Grafana folder and external providers",
Group: AlertRolesGroup,
Version: 2,
Version: 3,
Permissions: accesscontrol.ConcatPermissions(rulesReaderRole.Role.Permissions, []accesscontrol.Permission{
{
Action: accesscontrol.ActionAlertingRuleCreate,
@@ -84,7 +84,7 @@ var (
DisplayName: "Silences Editor",
Description: "Can add and update silences in Grafana and external providers",
Group: AlertRolesGroup,
Version: 1,
Version: 2,
Permissions: accesscontrol.ConcatPermissions(instancesReaderRole.Role.Permissions, []accesscontrol.Permission{
{
Action: accesscontrol.ActionAlertingInstanceCreate,
@@ -209,25 +209,7 @@ func (s *ServiceAccountsStoreImpl) RetrieveServiceAccount(ctx context.Context, o
return nil
})
if err != nil {
return nil, err
}
// Get Teams of service account. Can be optimized by combining with the query above
// in refactor
getTeamQuery := models.GetTeamsByUserQuery{UserId: serviceAccountID, OrgId: orgID}
if err := s.sqlStore.GetTeamsByUser(ctx, &getTeamQuery); err != nil {
return nil, err
}
teams := make([]string, len(getTeamQuery.Result))
for i := range getTeamQuery.Result {
teams[i] = getTeamQuery.Result[i].Name
}
serviceAccount.Teams = teams
return serviceAccount, nil
return serviceAccount, err
}
func (s *ServiceAccountsStoreImpl) RetrieveServiceAccountIdByName(ctx context.Context, orgID int64, name string) (int64, error) {
@@ -4,7 +4,6 @@ import (
"context"
"testing"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/serviceaccounts"
"github.com/grafana/grafana/pkg/services/serviceaccounts/tests"
"github.com/grafana/grafana/pkg/services/sqlstore"
@@ -107,20 +106,3 @@ func TestStore_RetrieveServiceAccount(t *testing.T) {
})
}
}
func TestStore_RetrieveServiceAccountWithTeams(t *testing.T) {
userToCreate := tests.TestUser{Login: "servicetestwithTeam@admin", IsServiceAccount: true}
db, store := setupTestDatabase(t)
user := tests.SetupUserServiceAccount(t, db, userToCreate)
team, err := store.sqlStore.CreateTeam("serviceTeam", "serviceTeam", user.OrgId)
require.NoError(t, err)
err = store.sqlStore.AddTeamMember(user.Id, user.OrgId, team.Id, false, models.PERMISSION_VIEW)
require.NoError(t, err)
dto, err := store.RetrieveServiceAccount(context.Background(), user.OrgId, user.Id)
require.NoError(t, err)
require.Equal(t, userToCreate.Login, dto.Login)
require.Len(t, dto.Teams, 1)
require.Equal(t, "serviceTeam", dto.Teams[0])
}
@@ -0,0 +1,68 @@
package accesscontrol
import (
"fmt"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
"xorm.io/xorm"
)
func AddActionNameMigrator(mg *migrator.Migrator) {
mg.AddMigration("RBAC action name migrator", &actionNameMigrator{})
}
type actionNameMigrator struct {
sess *xorm.Session
migrator *migrator.Migrator
migrator.MigrationBase
}
var _ migrator.CodeMigration = new(actionNameMigrator)
func (m *actionNameMigrator) SQL(migrator.Dialect) string {
return CodeMigrationSQL
}
func (m *actionNameMigrator) Exec(sess *xorm.Session, migrator *migrator.Migrator) error {
m.sess = sess
m.migrator = migrator
return m.migrateActionNames()
}
func (m *actionNameMigrator) migrateActionNames() error {
actionNameMapping := map[string]string{
"licensing:update": "licensing:write",
"reports.admin:create": "reports:create",
"reports.admin:write": "reports:write",
"org.users.role:update": accesscontrol.ActionOrgUsersWrite,
"users.authtoken:update": accesscontrol.ActionUsersAuthTokenUpdate,
"users.password:update": accesscontrol.ActionUsersPasswordUpdate,
"users.permissions:update": accesscontrol.ActionUsersPermissionsUpdate,
"users.quotas:update": accesscontrol.ActionUsersQuotasUpdate,
"teams.roles:list": "teams.roles:read",
"users.roles:list": "users.roles:read",
"users.authtoken:list": accesscontrol.ActionUsersAuthTokenList,
"users.quotas:list": accesscontrol.ActionUsersQuotasList,
"users.permissions:list": "users.permissions:read",
"alert.instances:update": accesscontrol.ActionAlertingInstanceUpdate,
"alert.rules:update": accesscontrol.ActionAlertingRuleUpdate,
}
for oldName, newName := range actionNameMapping {
_, err := m.sess.Table(&accesscontrol.Permission{}).Where("action = ?", oldName).Update(&accesscontrol.Permission{Action: newName})
if err != nil {
return fmt.Errorf("failed to update permission table for action %s: %w", oldName, err)
}
}
actionsToDelete := []string{"users.teams:read", "roles:list"}
for _, action := range actionsToDelete {
_, err := m.sess.Table(&accesscontrol.Permission{}).Where("action = ?", action).Delete(accesscontrol.Permission{})
if err != nil {
return fmt.Errorf("failed to update permission table for action %s: %w", action, err)
}
}
return nil
}
@@ -90,6 +90,7 @@ func (*OSSMigrations) AddMigration(mg *Migrator) {
accesscontrol.AddManagedPermissionsMigration(mg)
accesscontrol.AddManagedFolderAlertActionsMigration(mg)
accesscontrol.AddActionNameMigrator(mg)
}
func addMigrationLogMigrations(mg *Migrator) {
+12 -1
View File
@@ -310,12 +310,23 @@ func (ss *SQLStore) GetTeamsByUser(ctx context.Context, query *models.GetTeamsBy
query.Result = make([]*models.TeamDTO, 0)
var sql bytes.Buffer
var params []interface{}
params = append(params, query.OrgId, query.UserId)
sql.WriteString(getTeamSelectSQLBase([]string{}))
sql.WriteString(` INNER JOIN team_member on team.id = team_member.team_id`)
sql.WriteString(` WHERE team.org_id = ? and team_member.user_id = ?`)
err := sess.SQL(sql.String(), query.OrgId, query.UserId).Find(&query.Result)
if !ac.IsDisabled(ss.Cfg) {
acFilter, err := ac.Filter(query.SignedInUser, "team.id", "teams:id:", ac.ActionTeamsRead)
if err != nil {
return err
}
sql.WriteString(` and` + acFilter.Where)
params = append(params, acFilter.Args...)
}
err := sess.SQL(sql.String(), params...).Find(&query.Result)
return err
})
}
+8 -1
View File
@@ -222,7 +222,14 @@ func TestIntegrationTeamCommandsAndQueries(t *testing.T) {
err := sqlStore.AddTeamMember(userIds[0], testOrgID, groupId, false, 0)
require.NoError(t, err)
query := &models.GetTeamsByUserQuery{OrgId: testOrgID, UserId: userIds[0]}
query := &models.GetTeamsByUserQuery{
OrgId: testOrgID,
UserId: userIds[0],
SignedInUser: &models.SignedInUser{
OrgId: testOrgID,
Permissions: map[int64]map[string][]string{testOrgID: {ac.ActionOrgUsersRead: {ac.ScopeUsersAll}, ac.ActionTeamsRead: {ac.ScopeTeamsAll}}},
},
}
err = sqlStore.GetTeamsByUser(context.Background(), query)
require.NoError(t, err)
require.Equal(t, len(query.Result), 1)
+14 -1
View File
@@ -577,7 +577,20 @@ func (ss *SQLStore) GetSignedInUser(ctx context.Context, query *models.GetSigned
user.ExternalAuthId = ""
}
getTeamsByUserQuery := &models.GetTeamsByUserQuery{OrgId: user.OrgId, UserId: user.UserId}
// tempUser is used to retrieve the teams for the signed in user for internal use.
tempUser := &models.SignedInUser{
OrgId: user.OrgId,
Permissions: map[int64]map[string][]string{
user.OrgId: {
ac.ActionTeamsRead: {ac.ScopeTeamsAll},
},
},
}
getTeamsByUserQuery := &models.GetTeamsByUserQuery{
OrgId: user.OrgId,
UserId: user.UserId,
SignedInUser: tempUser,
}
err = ss.GetTeamsByUser(ctx, getTeamsByUserQuery)
if err != nil {
return err
@@ -617,7 +617,7 @@ func TestRulerAccess(t *testing.T) {
desc: "viewer request should fail",
url: "http://viewer:viewer@%s/api/ruler/grafana/api/v1/rules/default",
expStatus: http.StatusForbidden,
expectedMessage: `You'll need additional permissions to perform this action. Permissions needed: any of alert.rules:update, alert.rules:create, alert.rules:delete`,
expectedMessage: `You'll need additional permissions to perform this action. Permissions needed: any of alert.rules:write, alert.rules:create, alert.rules:delete`,
},
{
desc: "editor request should succeed",
+2 -2
View File
@@ -193,7 +193,7 @@ class UnThemedOrgRow extends PureComponent<OrgRowProps> {
const { currentRole, isChangingRole } = this.state;
const styles = getOrgRowStyles(theme);
const labelClass = cx('width-16', styles.label);
const canChangeRole = contextSrv.hasPermission(AccessControlAction.OrgUsersRoleUpdate);
const canChangeRole = contextSrv.hasPermission(AccessControlAction.OrgUsersWrite);
const canRemoveFromOrg = contextSrv.hasPermission(AccessControlAction.OrgUsersRemove);
const rolePickerDisabled = isExternalUser || !canChangeRole;
@@ -328,7 +328,7 @@ export class AddToOrgModal extends PureComponent<AddToOrgModalProps, AddToOrgMod
this.props.onOrgAdd(selectedOrg!.id, role);
// add the stored userRoles also
if (contextSrv.licensedAccessControlEnabled()) {
if (contextSrv.hasPermission(AccessControlAction.OrgUsersRoleUpdate)) {
if (contextSrv.hasPermission(AccessControlAction.OrgUsersWrite)) {
if (this.state.pendingUserId) {
await updateUserRoles(this.state.pendingRoles, this.state.pendingUserId!, this.state.pendingOrgId!);
// clear pending state
@@ -34,7 +34,7 @@ const ServiceAccountListItem = memo(
const displayRolePicker =
contextSrv.hasPermission(AccessControlAction.ActionRolesList) &&
contextSrv.hasPermission(AccessControlAction.ActionUserRolesList);
const enableRolePicker = contextSrv.hasPermission(AccessControlAction.OrgUsersRoleUpdate) && canUpdateRole;
const enableRolePicker = contextSrv.hasPermission(AccessControlAction.OrgUsersWrite) && canUpdateRole;
return (
<tr key={serviceAccount.id}>
+2 -2
View File
@@ -94,13 +94,13 @@ const UsersTable: FC<Props> = (props) => {
onBuiltinRoleChange={(newRole) => onRoleChange(newRole, user)}
roleOptions={roleOptions}
builtInRoles={builtinRoles}
disabled={!contextSrv.hasPermissionInMetadata(AccessControlAction.OrgUsersRoleUpdate, user)}
disabled={!contextSrv.hasPermissionInMetadata(AccessControlAction.OrgUsersWrite, user)}
/>
) : (
<OrgRolePicker
aria-label="Role"
value={user.role}
disabled={!contextSrv.hasPermissionInMetadata(AccessControlAction.OrgUsersRoleUpdate, user)}
disabled={!contextSrv.hasPermissionInMetadata(AccessControlAction.OrgUsersWrite, user)}
onChange={(newRole) => onRoleChange(newRole, user)}
/>
)}
+12 -13
View File
@@ -10,18 +10,17 @@ export type UserPermission = Record<string, boolean>;
export enum AccessControlAction {
UsersRead = 'users:read',
UsersWrite = 'users:write',
UsersTeamRead = 'users.teams:read',
UsersAuthTokenList = 'users.authtoken:list',
UsersAuthTokenUpdate = 'users.authtoken:update',
UsersPasswordUpdate = 'users.password:update',
UsersAuthTokenList = 'users.authtoken:read',
UsersAuthTokenUpdate = 'users.authtoken:write',
UsersPasswordUpdate = 'users.password:write',
UsersDelete = 'users:delete',
UsersCreate = 'users:create',
UsersEnable = 'users:enable',
UsersDisable = 'users:disable',
UsersPermissionsUpdate = 'users.permissions:update',
UsersPermissionsUpdate = 'users.permissions:write',
UsersLogout = 'users:logout',
UsersQuotasList = 'users.quotas:list',
UsersQuotasUpdate = 'users.quotas:update',
UsersQuotasList = 'users.quotas:read',
UsersQuotasUpdate = 'users.quotas:write',
ServiceAccountsRead = 'serviceaccounts:read',
ServiceAccountsCreate = 'serviceaccounts:create',
@@ -37,7 +36,7 @@ export enum AccessControlAction {
OrgUsersRead = 'org.users:read',
OrgUsersAdd = 'org.users:add',
OrgUsersRemove = 'org.users:remove',
OrgUsersRoleUpdate = 'org.users.role:update',
OrgUsersWrite = 'org.users:write',
LDAPUsersRead = 'ldap.user:read',
LDAPUsersSync = 'ldap.user:sync',
@@ -59,12 +58,12 @@ export enum AccessControlAction {
ActionTeamsPermissionsRead = 'teams.permissions:read',
ActionTeamsPermissionsWrite = 'teams.permissions:write',
ActionRolesList = 'roles:list',
ActionRolesList = 'roles:read',
ActionBuiltinRolesList = 'roles.builtin:list',
ActionTeamsRolesList = 'teams.roles:list',
ActionTeamsRolesList = 'teams.roles:read',
ActionTeamsRolesAdd = 'teams.roles:add',
ActionTeamsRolesRemove = 'teams.roles:remove',
ActionUserRolesList = 'users.roles:list',
ActionUserRolesList = 'users.roles:read',
DashboardsRead = 'dashboards:read',
DashboardsWrite = 'dashboards:write',
@@ -83,12 +82,12 @@ export enum AccessControlAction {
// Alerting rules
AlertingRuleCreate = 'alert.rules:create',
AlertingRuleRead = 'alert.rules:read',
AlertingRuleUpdate = 'alert.rules:update',
AlertingRuleUpdate = 'alert.rules:write',
AlertingRuleDelete = 'alert.rules:delete',
// Alerting instances (+silences)
AlertingInstanceCreate = 'alert.instances:create',
AlertingInstanceUpdate = 'alert.instances:update',
AlertingInstanceUpdate = 'alert.instances:write',
AlertingInstanceRead = 'alert.instances:read',
// Alerting Notification policies