What's new: RBAC behavior changes with Grafana 13
Grafana 13 tightens RBAC enforcement for custom roles, Terraform-managed roles, and role provisioning. Most users aren’t affected. If you maintain custom RBAC roles, especially roles with data source permissions scoped to specific UIDs, or roles using legacy annotation scopes, review your role definitions now to prevent errors.
We recommend updating affected roles proactively. Stricter enforcement is being rolled out progressively, and roles that contain the deprecated permissions described below will begin failing. Taking action now prevents disruption.
If role create, update, delete, or assignment operations start failing, check whether the role contains one of the permissions described below.
Data source permissions in global roles
Grafana 13 changes how data source permissions work in custom RBAC roles as data source APIs move toward strongly typed API groups. If you manage Grafana roles with Terraform, check any role that combines global = true with data source UID-scoped permissions.
What changed
- A global role should not grant access to one specific data source UID.
- Specific data source permissions should be defined on non-global roles, or managed through data source permission resources.
What you should do
- If a Terraform-managed
grafana_rolecontainsdatasources:uid:<uid>, recreate it as a non-global role. Grafana cannot update the global scope of an existing role in place. - If you manage data source permissions through Terraform data source permission resources, set
datasource_typewhen you know the data source type. - In Grafana Cloud, a compatibility layer is in place to reduce immediate impact. Self-managed Grafana users should update Terraform before upgrading to Grafana 13.
Before:
resource "grafana_role" "datasource_reader" {
name = "Datasource Reader"
uid = "datasource-reader"
global = true
permissions {
action = "datasources:read"
scope = "datasources:uid:prometheus_uid"
}
}After:
resource "grafana_role" "datasource_reader_v2" {
name = "Datasource Reader"
uid = "datasource-reader-v2"
global = false
permissions {
action = "datasources:read"
scope = "datasources:uid:prometheus_uid"
}
}Changing global = true to global = false on an existing role won’t work as it changes the scope of the role. Create the replacement role with a new UID, move assignments to it, then remove the old global role.
If you use data source permission resources directly, include the data source type:
resource "grafana_data_source_permission_item" "team_query" {
datasource_uid = grafana_data_source.prometheus.uid
datasource_type = "prometheus"
team = grafana_team.observability.id
permission = "Query"
}Dashboard annotation fixed roles were removed
The fixed roles fixed:annotations.dashboard:writer and fixed:annotations.dashboard:reader have been removed. These roles have been superseded by dashboard and folder permissions.
What changed
fixed:annotations.dashboard:writerno longer exists.fixed:annotations.dashboard:readerno longer exists.annotations:type:dashboardis a legacy scope and should not be used in new role definitions.
What you should do
- Remove
fixed:annotations.dashboard:writerandfixed:annotations.dashboard:readerfrom Terraform configurations and automation. - Remove permissions that use
annotations:type:dashboardfrom custom roles. - Use dashboard or folder permissions (
View,Edit,Admin) to grant access to dashboard annotations. - Use
fixed:annotations:readerandfixed:annotations:writerfor organization-level annotations. - To grant unrestricted access to all dashboard annotations, use
fixed:annotations.all:readerandfixed:annotations.all:writer. - If you define custom roles for organization annotations, use the specific annotation actions, such as
annotations:readorannotations:write, withannotations:type:organization.
Example replacement for organization annotations:
permissions {
action = "annotations:read"
scope = "annotations:type:organization"
}Dashboard annotation access now follows dashboard and folder access. If a user can view or edit the dashboard through dashboard/folder permissions, they get the matching access to that dashboard’s annotations.
Stop using annotations:* in custom roles
annotations:* is a legacy wildcard scope and is no longer granted by default. Do not use it in custom roles, Terraform, or provisioning.
What changed
- Grafana no longer expects custom roles to grant annotation access through
annotations:*. - Roles that still contain this scope may cause permission errors during role create, update, delete, or assignment operations.
- Some existing roles may need updating to remove this deprecated scope.
What you should do
- For organization-level annotations, use
annotations:type:organization. - For dashboard annotations, use dashboard or folder permissions instead of annotation-specific dashboard scopes.
- If your automation attempts to grant all annotation access, split the intent:
- Organization annotations:
annotations:type:organization - Dashboard annotations: dashboard or folder permissions, such as folder-level View, Edit, or Admin.
- Organization annotations:
- Do not recreate
annotations:*in Terraform after it has been removed. - If your role is stuck because Grafana refuses to update or delete it, contact support. The role may contain a deprecated permission that must be removed before Terraform or API updates can succeed.
Troubleshooting
If you see errors like these, inspect the role permissions:
[POST /access-control/roles][403] createRoleForbidden {"message":"Forbidden"}
[PUT /access-control/roles/{roleUID}][403] updateRoleForbidden {"message":"Forbidden"}
[PUT /access-control/roles/{roleUID}/assignments][403] setRoleAssignmentsForbidden {"message":"Forbidden"}Look for:
- Data source permissions with a specific
datasources:uid:<uid>scope on a global role fixed:annotations.dashboard:writerfixed:annotations.dashboard:readerannotations:type:dashboardannotations:*
After removing or replacing the deprecated permissions, re-run your Terraform apply or role provisioning.