Skip to content

Commit b3b4a9e

Browse files
authored
Docs: Add how to guide on using service accounts with app plugins (#1788)
1 parent d60d941 commit b3b4a9e

File tree

1 file changed

+148
-0
lines changed

1 file changed

+148
-0
lines changed
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
---
2+
id: use-a-service-account
3+
title: Use service accounts in Grafana app plugins
4+
description: How to use service accounts in Grafana app plugins to authenticate against the Grafana API.
5+
keywords:
6+
- grafana
7+
- plugin
8+
- app
9+
- service
10+
- bundling
11+
- authentication
12+
---
13+
14+
# Use service accounts in Grafana app plugins
15+
16+
App plugins with service accounts can authenticate against the Grafana API without requiring user intervention, allowing your plugin to access Grafana resources with specific permissions. Service accounts provide a secure way for your plugin to interact with Grafana's backend services and APIs.
17+
18+
Service accounts are managed automatically by Grafana when your plugin is registered. Unlike traditional authentication methods that might require user credentials or manual token generation.
19+
20+
## Before you begin
21+
22+
Ensure your development environment meets the following prerequisites:
23+
24+
- **Grafana version:** Use Grafana 10.3 or later
25+
- **Feature toggle:** Enable the `externalServiceAccounts` feature toggle. Refer to our documentation [on configuring Grafana feature toggles](https://grafana.com/docs/grafana/latest/setup-grafana/configure-grafana/#feature_toggles)
26+
- **Deployment type:** This feature currently **only supports single-organization deployments**
27+
28+
## Add service account configuration
29+
30+
To configure your app plugin to use a service account, add an `iam` section to your `plugin.json` file:
31+
32+
```json title="plugin.json"
33+
"iam": {
34+
"permissions": [
35+
{ "action": "dashboards:create", "scope": "folders:uid:*" },
36+
{ "action": "dashboards:read", "scope": "folders:uid:*"},
37+
{ "action": "dashboards:write", "scope": "folders:uid:*"},
38+
{ "action": "folders:read", "scope": "folders:uid:*"},
39+
{ "action": "folders:write", "scope": "folders:uid:*"},
40+
{ "action": "org.users:read", "scope": "users:*"},
41+
{ "action": "teams:read", "scope": "teams:*"},
42+
{ "action": "teams.permissions:read", "scope": "teams:*"}
43+
]
44+
}
45+
```
46+
47+
The `permissions` array defines the specific actions and scopes the service account can access. Refer to the [Grafana access control documentation](https://grafana.com/docs/grafana/latest/administration/roles-and-permissions/access-control/) for available permissions.
48+
49+
## Retrieve the service account token
50+
51+
When your plugin starts, Grafana automatically creates a service account with the specified permissions and provides a token to your plugin. Retrieve this token from the request context:
52+
53+
```go title="plugin.go"
54+
// Get the service account token from the plugin context
55+
cfg := backend.GrafanaConfigFromContext(req.Context())
56+
saToken, err := cfg.PluginAppClientSecret()
57+
if err != nil {
58+
http.Error(w, err.Error(), http.StatusInternalServerError)
59+
return
60+
}
61+
```
62+
63+
## Use the token for API requests
64+
65+
### Option 1: Configure the HTTP client with the token
66+
67+
Set up your HTTP client to include the token in all requests:
68+
69+
```go title="plugin.go"
70+
opts, err := settings.HTTPClientOptions(ctx)
71+
if err != nil {
72+
return nil, fmt.Errorf("http client options: %w", err)
73+
}
74+
75+
opts.Headers = map[string]string{"Authorization": "Bearer " + saToken}
76+
77+
// Client is now pre-configured with the bearer token
78+
client, err := httpclient.New(opts)
79+
if err != nil {
80+
return nil, fmt.Errorf("httpclient new: %w", err)
81+
}
82+
```
83+
84+
### Option 2: Add the token to individual requests
85+
86+
Alternatively, add the token to specific HTTP requests:
87+
88+
```go title="plugin.go"
89+
req, err := http.NewRequest("GET", grafanaAPIURL, nil)
90+
if err != nil {
91+
return nil, err
92+
}
93+
req.Header.Set("Authorization", "Bearer " + saToken)
94+
```
95+
96+
## Example implementation
97+
98+
Here's a simple example of a resource handler that uses the service account token to proxy requests to the Grafana API:
99+
100+
```go title="plugin.go"
101+
func (a *App) handleAPI(w http.ResponseWriter, req *http.Request) {
102+
// Get Grafana configuration from context
103+
cfg := backend.GrafanaConfigFromContext(req.Context())
104+
105+
// Get the base Grafana URL
106+
grafanaAppURL, err := cfg.AppURL()
107+
if err != nil {
108+
http.Error(w, err.Error(), http.StatusInternalServerError)
109+
return
110+
}
111+
112+
// Get the service account token
113+
saToken, err := cfg.PluginAppClientSecret()
114+
if err != nil {
115+
http.Error(w, err.Error(), http.StatusInternalServerError)
116+
return
117+
}
118+
119+
// Create a request to the Grafana API
120+
reqURL, err := url.JoinPath(grafanaAppURL, req.URL.Path)
121+
proxyReq, err := http.NewRequest("GET", reqURL, nil)
122+
123+
// Add the token to the request
124+
proxyReq.Header.Set("Authorization", "Bearer " + saToken)
125+
126+
// Make the request
127+
res, err := a.httpClient.Do(proxyReq)
128+
// Handle response...
129+
}
130+
```
131+
132+
## Limitations
133+
134+
- The service account is automatically created in the default organization (ID: `1`)
135+
- The plugin can only access data and resources within that specific organization
136+
- If your plugin needs to work with multiple organizations, this feature is not suitable
137+
138+
## Security considerations
139+
140+
- The service account cannot be modified or deleted by users
141+
- The token provides access to Grafana resources based on the permissions defined in your plugin
142+
- Do not expose the service account token to the frontend or end users
143+
144+
## Learn more
145+
146+
- [Grafana service accounts documentation](https://grafana.com/docs/grafana/latest/administration/service-accounts/)
147+
- [Grafana access control documentation](https://grafana.com/docs/grafana/latest/administration/roles-and-permissions/access-control/)
148+
- [Grafana plugin.json reference](https://grafana.com/developers/plugin-tools/reference-plugin-json)

0 commit comments

Comments
 (0)