本文使用 helm 方式部署 grafana 9 并同样将 keycloak 部署在 kubernetes 集群之上;接下来使用 keycloak 作为 grafana authentication,并实现 oauth2 的用户权限管理。
在Kubernetes 集群之上使用helm部署keycloak
在 kubernetes 集群安装 keycloak 有两种方式:
下面使用 offical 提供的方式进行部署
|
|
helm 部署完成后默认密码是存储在 secret 中,上面方式安装的密码默认为 admin/admin
Keycloak configuration
创建realm
Realm 管理这一组用户(users), 凭据(credentials), 角色(roles) 和 组(groups),realm之间是相互隔离,一个用户属于并登录到某个 realm,只能管理和验证其控制的用户。
下面为 grafana 创建一个 realm,如果你的环境已经存在通用的 realm,则可以使用这个 realm,默认 keycloak 的 realm 是 master,超级管理员属于这个 realm。
创建 client
Client 是可以请求Keycloak对用户进行身份验证的实体。最常见用途是希望使用Keycloak来保护自己并提供单点登录(SSO)解决方案的应用程序和服务。客户端也可以是只希望请求身份信息或访问令牌的实体,以便它们可以安全地调用由 Keycloak 保护的网络上的其他服务。因此,我们需要为 grafana 创建一个 client
根据 grafana 官方的指南,我们创建标准需如下所示
- Client ID:
grafana-oauth
- Enabled:
ON
- Client Protocol:
openid-connect
- Access Type:
confidential
- Standard Flow Enabled:
ON
- Implicit Flow Enabled:
OFF
- Direct Access Grants Enabled:
ON
- Root URL:
<grafana_root_url>
- Valid Redirect URIs:
<grafana_root_url>/login/generic_oauth
- Web Origins:
<grafana_root_url>
- Admin URL:
<grafana_root_url>
- Base URL:
<grafana_root_url>
Realm settings => Client policies => Policies
准备grafana chart包
添加 chart repo
|
|
选择 chart 包下载
|
|
修改 values.yaml 中 grafana.ini 部分,增加
|
|
这里主要修改三个部分
- server:
- root_url: 是在使用 keycloak 跳转时,redirect_uri 的地址,默认是 localhost:3000
- serve_from_sub_path: 从 root_url 设置中指定的子路径提供 Grafana 服务。 出于兼容性原因,默认情况下它设置为 false。
- auth: 配置登出时请求的 API,这个按照官方给出的配置即可。
- auth.generic_oauth: keycloak 的配置,这个按照官方给出的配置即可。
troubleshooting
Invalid redirect uri
|
|
遇到 Invalid redirect uri 错误时,检查 Access settings 配置,并将 grafana 的 auth.generic_oauth 按照下面配置即可
server 段
|
|
Generic OAuth 部分
#################################### Generic OAuth #######################
[auth.generic_oauth]
name = OAuth
enabled = true
allow_sign_up = true
client_id = Grafana
client_secret = ad35e16d-96d1-46ab-88d8-7cdb1512b608
scopes = openid profile email
email_attribute_name = email:primary
email_attribute_path =
login_attribute_path =
name_attribute_path =
role_attribute_path =
id_token_attribute_name =
auth_url = http://192.168.64.57:30708/auth/realms/devops/protocol/openid-connect/auth
token_url = http://192.168.64.57:30708/auth/realms/devops/protocol/openid-connect/token
api_url = http://192.168.64.57:30708/auth/realms/devops/protocol/openid-connect/userinfo
allowed_domains =
team_ids =
allowed_organizations =
tls_skip_verify_insecure = false
tls_client_cert =
tls_client_key =
tls_client_ca =
login.OAuthLogin(state mismatch)
这个错误是没有配置对应user的状态或者没有配置email导致,如果配置了 email,那么吧用户放置到对应组中就恢复了
配置权限
如果使用了 role 作为权限分配,那么按照官方的配置即可,如果使用 group,则需要使用下面的规则
|
|
这个表达式是一个条件表达式,用于根据用户所属的组分配角色属性值。下面是对每个字符和子表达式的翻译解释:
- role_attribute_path : 角色属性路径,表示根据条件表达式的结果来确定角色属性值。
contains(groups[*], 'admin')
: 检查用户所属的组列表中是否包含 admin 组。- &&: 逻辑与运算符,用于组合多个条件,表示两个条件都为真时整个表达式为真。
- Admin: 如果
contains(groups[*], 'admin')
为真,将角色属性设置为 Admin。 ||
: 逻辑或运算符,用于组合多个条件,表示任意一个条件为真时整个表达式为真。contains(groups[*], 'editer')
: 检查用户所属的组列表中是否包含 editer 组。'Editor'
: 如果contains(groups[*], 'editer')
为真,将角色属性设置为 Editor。contains(groups[*], 'viewer')
: 检查用户所属的组列表中是否包含 viewer 组。'Viewer'
: 如果contains(groups[*], 'viewer')
为真,将角色属性设置为 Viewer。