Grafana 支持 Generic OAuth,可以直接对接 Authentik 的 OAuth2/OpenID Connect Provider。配置过程本身并不复杂,但有两个很容易踩到的坑:
- 没有配置
login_attribute_path时,Grafana 可能把 email 当作登录名。 - OIDC 角色映射为
Admin时,用户只是 Organization Admin,并不具备安装插件所需的 Server Admin 权限。
本文使用示例参数,完整说明安装、OIDC 对接、Secret 管理、用户名映射、管理员权限和常见问题。
1. 示例参数
本文统一使用以下占位参数:
| 参数 | 示例值 |
|---|---|
| Grafana 地址 | https://grafana.example.com |
| Authentik 地址 | https://auth.example.com |
| Kubernetes namespace | monitoring |
| OIDC Secret | grafana-oidc |
| Authentik 管理员组 | Grafana Server Admins |
| Authentik Provider slug | grafana |
请根据实际环境替换域名、namespace、组名、版本和镜像 digest。不要把真实 client secret、用户名、邮箱、内网 IP 或集群信息写入公开文章或 Git 仓库。
2. 在 Authentik 中创建 Provider
在 Authentik 管理后台创建 OAuth2/OpenID Provider。
建议参数:
| 配置项 | 建议值 |
|---|---|
| Client type | Confidential |
| Redirect URI | https://grafana.example.com/login/generic_oauth |
| Scopes | openid email profile |
| Signing Key | 选择可用的签名证书 |
| Subject mode | 使用稳定且不会随用户名变化的用户标识 |
Redirect URI 必须和 Grafana 实际回调地址完全一致,包括协议、域名和路径。
随后创建 Authentik Application,并关联刚才创建的 Provider。
3. 确认 OIDC claims
Grafana至少需要以下 claims:
{
"sub": "stable-user-id",
"preferred_username": "alice",
"email": "alice@example.com",
"name": "Alice",
"groups": ["Grafana Server Admins"]
}
各字段用途:
sub:外部身份的稳定唯一标识。preferred_username:Grafana login。email:Grafana email。name:显示名称。groups:用于角色映射,必须是数组。
如果 UserInfo 中没有 preferred_username 或 groups,需要在 Authentik Provider 中检查 profile scope 和 Property Mapping。
4. 使用 Kubernetes Secret 保存 OIDC 凭据
不要把 client_id 和 client_secret 写进 Helm values、ConfigMap 或 Git。
先交互输入凭据,避免 secret 直接进入 shell history:
printf 'Authentik client_id: '
IFS= read -r GRAFANA_OIDC_CLIENT_ID
printf 'Authentik client_secret: '
IFS= read -rs GRAFANA_OIDC_CLIENT_SECRET
printf '\n'
创建 Kubernetes Secret:
kubectl create namespace monitoring --dry-run=client -o yaml \
| kubectl apply -f -
kubectl -n monitoring create secret generic grafana-oidc \
--from-literal=GF_AUTH_GENERIC_OAUTH_CLIENT_ID="$GRAFANA_OIDC_CLIENT_ID" \
--from-literal=GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET="$GRAFANA_OIDC_CLIENT_SECRET" \
--dry-run=client -o yaml \
| kubectl apply -f -
unset GRAFANA_OIDC_CLIENT_ID GRAFANA_OIDC_CLIENT_SECRET
只检查 Secret key,不输出值:
kubectl -n monitoring get secret grafana-oidc -o json \
| jq -r '.data | keys[]'
预期输出:
GF_AUTH_GENERIC_OAUTH_CLIENT_ID
GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET
Kubernetes Secret 的 .data 只是 Base64 编码,并不等于加密。生产环境仍需要:
- 限制 Secret RBAC。
- 启用 etcd encryption at rest。
- 避免在终端、CI 日志和排障记录中展开 Secret 值。
- 使用 External Secrets、SOPS 或 Sealed Secrets 管理 GitOps 场景中的敏感信息。
5. Grafana Helm values
下面只展示与 Grafana 和 OIDC 相关的核心参数:
grafana:
enabled: true
replicas: 1
image:
registry: docker.io
repository: grafana/grafana
tag: "<pinned-version>"
sha: "<verified-sha256>"
pullPolicy: IfNotPresent
deploymentStrategy:
type: Recreate
envFromSecret: grafana-oidc
persistence:
enabled: true
type: pvc
accessModes:
- ReadWriteOnce
size: 10Gi
storageClassName: "<storage-class>"
ingress:
enabled: false
grafana.ini:
auth.generic_oauth:
name: authentik
enabled: true
auto_login: true
allow_sign_up: true
allow_assign_grafana_admin: true
scopes: openid email profile
auth_url: https://auth.example.com/application/o/authorize/
token_url: https://auth.example.com/application/o/token/
api_url: https://auth.example.com/application/o/userinfo/
login_attribute_path: preferred_username
role_attribute_path: "contains(groups, 'Grafana Server Admins') && 'GrafanaAdmin' || 'Viewer'"
users:
allow_sign_up: false
security:
cookie_secure: true
cookie_samesite: strict
disable_gravatar: true
server:
domain: grafana.example.com
root_url: https://grafana.example.com/
enforce_domain: true
5.1 为什么使用 envFromSecret
Secret key 使用 Grafana 环境变量名称:
GF_AUTH_GENERIC_OAUTH_CLIENT_ID
GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET
Grafana启动时通过环境变量读取 OIDC 凭据,values 和由 Helm 生成的 ConfigMap 中不需要出现明文 secret。
5.2 为什么使用 Recreate
当单副本 Grafana 使用 RWO PVC 时,RollingUpdate 可能先创建新 Pod。旧 Pod 尚未释放磁盘,新 Pod 就会发生 Multi-Attach。
因此单副本 RWO 场景建议:
deploymentStrategy:
type: Recreate
它会先删除旧 Pod,再创建新 Pod。代价是升级时存在短暂中断,但不会发生新旧 Pod 争抢同一块 RWO 存储的问题。
6. 用户名映射
Grafana Generic OAuth 会从 ID Token、UserInfo 和 Access Token 中寻找用户 login。如果没有找到合适字段,可能回退为 email。
显式配置:
login_attribute_path: preferred_username
这样 Grafana 会把 Authentik 的 preferred_username 作为 login,而不是把 email 显示成登录名。
需要同时确保:
scopes: openid email profile
并确认 Authentik确实返回:
{
"preferred_username": "alice"
}
修改 claim 映射后,已有用户必须退出并重新登录,才会触发身份同步。
7. 管理员权限映射
Grafana 的 Admin 和 GrafanaAdmin 不是同一个权限级别。
| 角色 | 权限 |
|---|---|
Viewer | 查看 dashboard |
Editor | 编辑 dashboard 等组织资源 |
Admin | Organization Admin |
GrafanaAdmin | Server Admin,管理整个 Grafana 实例 |
安装、升级或删除插件需要 Server Admin。如果只映射为:
Admin
用户可能看到:
You do not have permission to install this plugin.
正确配置需要同时包含:
allow_assign_grafana_admin: true
role_attribute_path: "contains(groups, 'Grafana Server Admins') && 'GrafanaAdmin' || 'Viewer'"
生产环境建议创建专用的 Grafana Server Admin 组,不要直接复用范围过大的全局管理员组。
8. HTTPS 和回调地址
Grafana对外地址应使用 HTTPS:
server:
domain: grafana.example.com
root_url: https://grafana.example.com/
enforce_domain: true
同时启用安全 Cookie:
security:
cookie_secure: true
cookie_samesite: strict
无论使用 Ingress、Gateway API 还是其他 HTTPS 反向代理,都需要:
- 保留原始
Host。 - 正确传递
X-Forwarded-Proto: https。 - 使用覆盖 Grafana 域名的有效证书。
- 将 HTTP 请求跳转到 HTTPS。
- 在 Authentik 中配置完全一致的 Redirect URI。
9. Helm 安装
固定 Chart 版本并下载到本地:
CHART_VERSION="<pinned-chart-version>"
helm repo add prometheus-community \
https://prometheus-community.github.io/helm-charts
helm repo update
helm pull prometheus-community/kube-prometheus-stack \
--version "$CHART_VERSION" \
--destination .cache/charts
对下载的 Chart 计算并人工核对 SHA256:
sha256sum ".cache/charts/kube-prometheus-stack-${CHART_VERSION}.tgz"
渲染和 lint:
helm template monitoring-stack \
".cache/charts/kube-prometheus-stack-${CHART_VERSION}.tgz" \
--namespace monitoring \
-f values.yaml \
> rendered.yaml
helm lint --strict \
".cache/charts/kube-prometheus-stack-${CHART_VERSION}.tgz" \
-f values.yaml
安装:
helm upgrade --install monitoring-stack \
".cache/charts/kube-prometheus-stack-${CHART_VERSION}.tgz" \
--namespace monitoring \
--create-namespace \
-f values.yaml \
--wait \
--timeout 30m
生产环境不要使用 latest,也不要在正式安装时重新按版本标签拉取未经当前变更审查的 Chart。
10. 登录验收
先检查 Pod:
kubectl -n monitoring get deployment,pod,pvc \
-l app.kubernetes.io/name=grafana -o wide
检查健康状态:
curl -fsS https://grafana.example.com/api/health
预期包含:
{
"database": "ok"
}
登录后确认:
- 登录名是
preferred_username,不是 email。 - email 字段仍正确显示。
- 管理员组成员拥有 Server Admin。
- 普通用户默认是 Viewer。
- OIDC client secret 没有出现在 ConfigMap 或 rendered YAML 中。
修改 claim、用户名或组以后,需要访问:
https://grafana.example.com/logout
然后重新登录。如果启用了 auto_login,Grafana会自动重新进入 Authentik 登录流程。
11. Secret 轮换
在 Authentik 中生成新 client secret 后,重新应用 Secret:
printf 'Authentik client_id: '
IFS= read -r GRAFANA_OIDC_CLIENT_ID
printf 'New Authentik client_secret: '
IFS= read -rs GRAFANA_OIDC_CLIENT_SECRET
printf '\n'
kubectl -n monitoring create secret generic grafana-oidc \
--from-literal=GF_AUTH_GENERIC_OAUTH_CLIENT_ID="$GRAFANA_OIDC_CLIENT_ID" \
--from-literal=GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET="$GRAFANA_OIDC_CLIENT_SECRET" \
--dry-run=client -o yaml \
| kubectl apply -f -
unset GRAFANA_OIDC_CLIENT_ID GRAFANA_OIDC_CLIENT_SECRET
外部 Secret 更新通常不会自动刷新已有 Pod 的环境变量,因此需要执行:
kubectl -n monitoring rollout restart deployment/<grafana-deployment>
kubectl -n monitoring rollout status deployment/<grafana-deployment> \
--timeout=10m
随后重新完成一次 OIDC 登录验收。
12. ConfigMap 还是 Helm values
生产环境推荐:
Helm values 保存非敏感配置
Kubernetes Secret 保存 OIDC 凭据
Helm 自动生成和管理 ConfigMap
不建议手工修改 Grafana ConfigMap,原因是:
- Helm upgrade 可能覆盖手工修改。
- 容易形成 values、rendered YAML 和 live ConfigMap 之间的配置漂移。
- ConfigMap不能保存 client secret。
- Helm values 更适合做 render、lint、diff 和 rollback。
因此,values 是配置源,ConfigMap 是 Helm 渲染产物,Secret 是敏感信息来源。
13. 常见问题
登录名仍然是 email
检查:
login_attribute_path: preferred_username
并确认 Authentik UserInfo 中存在 preferred_username。已有用户需要退出并重新登录。
用户是 Admin,但不能安装插件
Admin 只是 Organization Admin。需要:
allow_assign_grafana_admin: true
role_attribute_path: "contains(groups, 'Grafana Server Admins') && 'GrafanaAdmin' || 'Viewer'"
确认 groups claim 是数组,组名大小写和空格完全一致。
出现 invalid_client
检查:
- client ID 和 client secret 是否来自同一个 Authentik Provider。
- Secret key 名是否正确。
- Secret 轮换后 Grafana Pod 是否已重启。
- Provider 是否为 Confidential client。
出现 redirect_uri mismatch
检查 Authentik Redirect URI:
https://grafana.example.com/login/generic_oauth
以及 Grafana:
root_url: https://grafana.example.com/
修改配置后角色没有变化
Pod 重启只会加载新配置,不会自动刷新现有用户的 OAuth claims。用户必须退出并重新登录。
如果浏览器持续复用 Authentik 会话,可以:
- 使用无痕窗口。
- 在 Authentik 中撤销应用会话。
- 同时退出 Authentik。
14. 关于插件安装
Server Admin 权限只代表用户有能力安装插件,不代表可以绕过供应链审查。
生产环境安装插件前仍应:
- 固定插件版本。
- 获取并验证官方 SHA256。
- 禁止使用
latest。 - 优先离线缓存或预置插件。
- 在测试环境验证兼容性后再进入生产。
