Keycloak Multitenancy Authentication in Grafana with Helm

Hello Grafana Community,

I am deploying Grafana v11.1.0 using Helm and want to enable Keycloak multitenancy authentication.
The goal is to allow a single Grafana instance to authenticate and authorize multiple users from multiple Keycloak realms, while respecting their roles.

Here are my specific questions:

  1. Is it possible to configure Grafana to authenticate users from multiple Keycloak realms in a single instance?
  2. If yes, how can this be achieved when deploying Grafana using Helm?

The current setup works well for a single Keycloak realm. However, I want to enable Grafana to authenticate users from multiple Keycloak realms in a single instance.
values.yaml -

Keycloak OAuth configuration

auth:
generic_oauth:
enabled: “true”
name: “Keycloak-OAuth”
allow_sign_up: “true”
client_id: “grafana-oauth” # Replace with your client ID
client_secret: “x7WAZsl2lHWeZsEoUNArnWCLPYZVTOtX” # Replace with your client secret
scopes: “openid email profile offline_access roles”
email_attribute_path: “email”
login_attribute_path: “preferred_username”
name_attribute_path: “full_name”
auth_url: “auth url”
token_url: “Keycloak token url”
api_url: “http://localhost:8080/realms/grafana/protocol/openid-connect/userinfo” # Replace with your Keycloak IP and realm
role_attribute_path: “contains(realm_access.roles[], ‘admin’) && ‘Admin’ || contains(realm_access.roles[], ‘editor’) && ‘Editor’ ||‘Viewer’”
groups_attribute_path: “groups”
signout_redirect_url: “http://localhost:8080/realms/grafana/protocol/openid-connect/logout?post_logout_redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Flogin

deployments.yaml -
spec:
selector:
matchLabels:
app: grafana
template:
metadata:
labels:
app: grafana
spec:
containers:
- name: grafana
image: “{{ .Values.container.image.repository }}:{{ .Values.container.image.tag }}”
imagePullPolicy: IfNotPresent
ports:
- containerPort: 3000
name: http-grafana
protocol: TCP
env:
- name: GF_AUTH_GENERIC_OAUTH_ENABLED
value: “{{ .Values.auth.generic_oauth.enabled }}”
- name: GF_AUTH_GENERIC_OAUTH_NAME
value: “{{ .Values.auth.generic_oauth.name }}”
- name: GF_AUTH_GENERIC_OAUTH_ALLOW_SIGN_UP
value: “{{ .Values.auth.generic_oauth.allow_sign_up }}”
- name: GF_AUTH_GENERIC_OAUTH_CLIENT_ID
value: “{{ .Values.auth.generic_oauth.client_id }}”
- name: GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET
value: “{{ .Values.auth.generic_oauth.client_secret }}”
- name: GF_AUTH_GENERIC_OAUTH_SCOPES
value: “{{ .Values.auth.generic_oauth.scopes }}”
- name: GF_AUTH_GENERIC_OAUTH_EMAIL_ATTRIBUTE_PATH
value: “{{ .Values.auth.generic_oauth.email_attribute_path }}”
- name: GF_AUTH_GENERIC_OAUTH_LOGIN_ATTRIBUTE_PATH
value: “{{ .Values.auth.generic_oauth.login_attribute_path }}”
- name: GF_AUTH_GENERIC_OAUTH_NAME_ATTRIBUTE_PATH
value: “{{ .Values.auth.generic_oauth.name_attribute_path }}”
- name: GF_AUTH_GENERIC_OAUTH_AUTH_URL
value: “{{ .Values.auth.generic_oauth.auth_url }}”
- name: GF_AUTH_GENERIC_OAUTH_TOKEN_URL
value: “{{ .Values.auth.generic_oauth.token_url }}”
- name: GF_AUTH_GENERIC_OAUTH_API_URL
value: “{{ .Values.auth.generic_oauth.api_url }}”
- name: GF_AUTH_GENERIC_OAUTH_ROLE_ATTRIBUTE_PATH
value: “{{ .Values.auth.generic_oauth.role_attribute_path }}”
- name: GF_AUTH_GENERIC_OAUTH_GROUPS_ATTRIBUTE_PATH
value: “{{ .Values.auth.generic_oauth.groups_attribute_path }}”
- name: GF_AUTH_GENERIC_OAUTH_SIGNOUT_REDIRECT_URL
value: “{{ .Values.auth.generic_oauth.signout_redirect_url }}”

Can you please guide us with the correct approach.

Thanks,
Reema Sahu