Skip to content

maxuru ~ % cat grafana/restrict-data-source-permissions

Restrict what Grafana's data source credentials can do

Severity: mediumApplies to: Grafana 11.x / 12.x / 13.x
The fix
-- PostgreSQL: a data source account that can only read what it must
CREATE ROLE grafana_ro LOGIN PASSWORD 'generated-value';
GRANT CONNECT ON DATABASE appdb TO grafana_ro;
GRANT USAGE ON SCHEMA metrics TO grafana_ro;
GRANT SELECT ON ALL TABLES IN SCHEMA metrics TO grafana_ro;
ALTER DEFAULT PRIVILEGES IN SCHEMA metrics GRANT SELECT ON TABLES TO grafana_ro;

The control is not really configured in Grafana. It is configured in each system Grafana connects to.

Everything else on this checklist protects Grafana. This one limits what Grafana’s compromise is worth — and it is the only control here that keeps working after every other one has failed.

Grafana stores working credentials for each data source and uses them to run queries. Those credentials are frequently over-privileged, because the person adding the data source used one that was already available and the dashboard only had to work:

  • the application’s own database user, which can write
  • a cloud key with broad read access across services, not just metrics
  • an Elasticsearch elastic superuser rather than a scoped API key
  • a database superuser, because it was the one in the password manager

A Grafana breach with those stored is a breach of every one of those systems, at that privilege level. With read-only scoped accounts it is a disclosure of whatever the dashboards already showed — bad, bounded, and recoverable.

The site has a page for most of these; the Grafana-specific instruction is to create a dedicated account per data source rather than reusing anything.

  • PostgreSQL — a LOGIN role with SELECT only, as above. See least-privilege roles. Grafana can enforce read-only at its end too, but that is a client-side guard, not a permission.
  • MySQL / MariaDBGRANT SELECT ON metrics.* TO 'grafana_ro'@'10.0.1.5', scoped by host as well as schema. See least-privilege grants.
  • Elasticsearch — an API key with read privileges on the specific indices, never the elastic superuser. See API keys and least privilege.
  • Prometheus — has no built-in auth; the control is network placement plus a proxy in front. Note that Prometheus’s own admin API can delete series if it is enabled, so do not let Grafana’s path reach it.
  • Cloud providers — a role scoped to the metrics API only. This is where over-privilege is most common and most expensive, because the same key often carries far more than monitoring.

Two are worth knowing about:

[security]
data_source_proxy_whitelist =

Empty by default, meaning no restriction. Populating it with the host:port pairs your data sources actually use limits where Grafana’s proxy will send requests — a useful guard against a data source being edited to point somewhere internal, which is a server-side request forgery in everything but name. Anyone who can add or edit a data source in Grafana can otherwise aim it at any address Grafana can reach, including cloud metadata at 169.254.169.254.

The second is who can edit data sources at all. In Grafana that is Admin role within an organisation. Keep that list short — data source edit rights are effectively “make Grafana connect to arbitrary hosts with stored credentials”.