Access Management
A profile token has full authority over its own queries. Any other caller reaches the /sql routes through
an Access Management policy: the policy targets a Run user or an
analysis and grants actions on the SQL Query resource, matched by a query's id, its tags, or any query.
Whatever the grant, the operation runs under the owning profile: its plan, its limits, and its data scope.
Actions per target
Run users are consumers of stored queries: they can discover and run what a policy grants, never manage. This restriction is enforced on the server, so a policy that grants a management action to a Run user is refused at request time.
| Action | Run user | Analysis | What it gates |
|---|---|---|---|
| Access | Yes | Yes | Listing queries and reading one query's details and version history |
| Execute | Yes | Yes | Running a stored query |
| Create | No | Yes | Creating a stored query |
| Edit | No | Yes | Replacing a stored query |
| Delete | No | Yes | Deleting a stored query |
An analysis with any allow rule on the SQL Query resource can also read the
schema discovery catalog (GET /sql/tables).
Only stored queries can be executed, so every executable query has the id and tags a policy matches.
How policies match queries
A permission rule names the resource in one of the standard forms:
- Any: every stored query on the profile.
- ID: one specific query.
- Tag: queries carrying a given tag key and value.
- Tag match: the query's tag value must equal the target's own tag value for the same key. Useful to hand each Run user the queries labeled with their own organization tag.
Create is the exception: the query does not exist yet, so the rule matches against the tags the create request carries. An id rule can never match a create, and the policy editor does not offer it.
Listing
GET /sql with a Run-user or analysis token returns only the queries the caller's policies grant with
Access. Filters, field selection, and pagination work as usual within that subset. A caller with no
matching grant gets an empty list, not an error.
Example
Allow every Run user to see and run the queries tagged audience=dashboard:
{
"name": "Dashboard queries for Run users",
"active": true,
"targets": [["run_user"]],
"permissions": [
{
"effect": "allow",
"action": ["access", "execute"],
"resource": ["sql", "tag.key", "audience", "tag.value", "dashboard"]
}
]
}
Deny rules work as in every other Access Management policy and override matching allow rules.
What a grant exposes
Granting execution of a query grants its full result set. The policy decides which queries a caller may run, never which rows or columns come back: the query runs with the profile's data access, and no permission in the policy (device, entity, or any other resource) applies to the rows returned. A Run user with a deny rule on a device still receives that device's data if a granted query selects it.
Write the query so it returns only what its audience may see, and treat the result set as visible to everyone the policy targets.
Scoping pattern
The query itself is the security boundary. To control what each Run user sees:
- Author one query per audience. Put the restriction inside the SQL: fixed device ids, a tag-scoped fleet function, and only the columns that audience may see. A query per Run user, per organization, or per role are all valid granularities.
- Label the query for its audience with a tag, for example
audience=acme-corpon the query and the same tag on the Acme Run users. - Grant narrowly. Match the rule by the query's id, by its audience tag, or with tag match so the
rule resolves per caller: a
tag matchrule on the keyaudiencegrants each Run user only the queries whoseaudiencetag value equals their own. One policy then serves every organization without listing ids.
Avoid the any form (every stored query) unless every query on the profile is safe for every target the policy reaches, including queries created later.