Grafana deployment with Keycloak OAuth2 SSO configuration
A basic example of a Grafana Deployment that overrides generic oauth configuration, it’s important to note that most configuration that is valid in the grafana
container can be done with grafana-operator.
Steps
Create Keycloak Client for Grafana
Follow official Grafana guide in how to create a Keycloak client and role mappers for Grafana here.
Create a Kubernetes Secret
In order to safely store the client-id and client-secret for the Keycloak client you have created in the first step, we recommend you creating a Kubernetes secrets to store the client-id and client-secret that Keycloak will use.
The grafana-operator is agnostic to any secret management solution you might use to get this secret (Vault, external-secrets, vanilla K8s secrets, etc).
apiVersion: v1
data:
client-id: c29tZXJlYWxseWxvbmdzZWNyZXRqdXN0dG9jb3ZlcnN0dWZmCg==
client-secret: c29tZXJlYWxseWxvbmdzZWNyZXRqdXN0dG9jb3ZlcnN0dWZmCg==
kind: Secret
metadata:
name: grafana-oauth
type: Opaque
Creating our Grafana Instance
Create a Grafana instance overriding the configuration for auth.generic_oauth:
.
apiVersion: grafana.integreatly.org/v1beta1
kind: Grafana
metadata:
name: grafana
labels:
dashboards: "grafana"
spec:
config:
log:
mode: "console"
auth:
disable_login_form: "false"
auth.generic_oauth:
# For variables see https://grafana.com/docs/grafana/latest/setup-grafana/configure-grafana/#env-provider
enabled: "true"
name: "Keycloak SSO"
allow_sign_up: "true"
client_id: ${AUTH_CLIENT_ID}
client_secret: ${AUTH_CLIENT_SECRET}
scopes: "openid email profile offline_access roles"
email_attribute_path: email
login_attribute_path: username
name_attribute_path: full_name
groups_attribute_path: groups
auth_url: "https://<PROVIDER_DOMAIN>/realms/<REALM_NAME>/protocol/openid-connect/auth"
token_url: "https://<PROVIDER_DOMAIN>/realms/<REALM_NAME>/protocol/openid-connect/token"
api_url: "https://<PROVIDER_DOMAIN>/realms/<REALM_NAME>/protocol/openid-connect/userinfo"
role_attribute_path: "contains(roles[*], 'admin') && 'Admin' || contains(roles[*], 'editor') && 'Editor' || 'Viewer'"
...
Now, we need to set secretKeyRef
to the Grafana container to pass the values inside the secret you have created in the previous step as environment variables. Please make sure to point to the right secret name and key.
...
deployment:
spec:
template:
spec:
containers:
- name: grafana
env:
- name: AUTH_CLIENT_ID
valueFrom:
secretKeyRef:
name: grafana-oauth
key: client-id
- name: AUTH_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: grafana-oauth
key: client-secret
...
Full configuration is below.
apiVersion: v1
data:
client-id: c29tZXJlYWxseWxvbmdzZWNyZXRqdXN0dG9jb3ZlcnN0dWZmCg==
client-secret: c29tZXJlYWxseWxvbmdzZWNyZXRqdXN0dG9jb3ZlcnN0dWZmCg==
kind: Secret
metadata:
name: grafana-oauth
namespace: monitoring
type: Opaque
---
apiVersion: grafana.integreatly.org/v1beta1
kind: Grafana
metadata:
name: grafana
labels:
dashboards: "grafana"
spec:
config:
log:
mode: "console"
auth:
disable_login_form: "false"
auth.generic_oauth:
# For variables see https://grafana.com/docs/grafana/latest/setup-grafana/configure-grafana/#env-provider
enabled: "true"
name: "Keycloak SSO"
allow_sign_up: "true"
client_id: ${AUTH_CLIENT_ID}
client_secret: ${AUTH_CLIENT_SECRET}
scopes: "openid email profile offline_access roles"
email_attribute_path: email
login_attribute_path: username
name_attribute_path: full_name
groups_attribute_path: groups
auth_url: "https://<PROVIDER_DOMAIN>/realms/<REALM_NAME>/protocol/openid-connect/auth"
token_url: "https://<PROVIDER_DOMAIN>/realms/<REALM_NAME>/protocol/openid-connect/token"
api_url: "https://<PROVIDER_DOMAIN>/realms/<REALM_NAME>/protocol/openid-connect/userinfo"
role_attribute_path: "contains(roles[*], 'admin') && 'Admin' || contains(roles[*], 'editor') && 'Editor' || 'Viewer'"
server:
root_url: https://grafana.your-domain.com
deployment:
spec:
template:
spec:
containers:
- name: grafana
env:
- name: AUTH_CLIENT_ID
valueFrom:
secretKeyRef:
name: grafana-oauth
key: client-id
- name: AUTH_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: grafana-oauth
key: client-secret
image: grafana/grafana:10.0.3
ingress:
metadata:
annotations:
kubernetes.io/ingress.class: nginx
external-dns.alpha.kubernetes.io/hostname: grafana.your-domain.com
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: nginx
rules:
- host: grafana.your-domain.com
http:
paths:
- backend:
service:
name: grafana-service
port:
number: 3000
path: /
pathType: Prefix
tls:
- hosts:
- grafana.your-domain.com
secretName: grafana-tls-secret