In this blog, we will learn to deploy & set up Apache Superset with Keycloak authentication. Apache Superset is an open-source software application for data exploration and data visualization able to handle data at a petabyte scale. Keycloak is an open-source software product to allow single sign-on with Identity and Access Management aimed at modern applications and services.
Prerequisites
- Keycloak server
- Keycloak Realm
- Keycloak Client & broker configured with OIDC protocols.
- client_secret.json
- A PostgreSQL Instance deployed on the same Kubernetes cluster
- Helm installed in system & basic knowledge of Helm.
- Admin username & password of PostgreSQL instance
- Superset Database created in PostgreSQL (If not then follow step 3)
- Optionally Cert-manager if you want to have SSL certificates on hostnames.
Before You begin
1 Clone this Repo for the scripts
git clone https://github.com/knoldus/apache-superset-with-keycloak.git
2 Change directory into the cloned repo
cd apache-superset-with-keycloak
Steps to setup
1. Generate your client_secret.json file for your client authentication
The content of file should look like this. Change & replace with your values
{
"web": {
"issuer": "http://<keycloakdomain>/auth/realms/<realmName>",
"auth_uri": "http://<keycloakdomain>/auth/realms/<realmName>/protocol/openid-connect/auth",
"client_id": "<ClientID>",
"client_secret": "<ClientSecret>",
"redirect_uris": ["http://<keycloakdomain>/*"],
"userinfo_uri": "http://<keycloakdomain>/auth/realms/<realmName>/protocol/openid-connect/userinfo",
"token_uri": "http://<keycloakdomain>/auth/realms/<realmName>/protocol/openid-connect/token",
"token_introspection_uri": "http://<keycloakdomain>/auth/realms/<realmName>/protocol/openid-connect/token/introspect"
}
}
Flatten the JSON file with this command
cat client_secret.json|tr -d "\n"
2. Replace the copied flatten content of client_secret.json file in .Values.extraSecrets.client_secret.json
extraSecrets:
client_secret.json: |
<YOUR_CLIENT_SECRET_JSON_STRING>
3. Replace placeholders with username, password, and service name for PostgreSQL
supersetNode:
connections:
db_host: <POSTGRES_SERVICE_NAME>.<NAMESPACE>.svc.cluster.local
db_user: <USERNAME>
db_pass: <PASSWORD>
extraEnv:
DATABASE_HOST: <POSTGRES_SERVICE_NAME>.NAMESPACE.svc.cluster.local
DATABASE_PASSWORD: <PASSWORD>
DATABASE_USER: <USERNAME>
POSTGRES_USER: <USERNAME>
POSTGRES_PASSWORD: <PASSWORD>
4. Add Realm name of keycloak
extraEnv:
OIDC_OPENID_REALM: <YOUR_REALM_NAME>
5. Keycloak_security_manager.py script in keycloak-values.yaml
Values.extraSecrets.keycloak_security_manager.py
from flask_appbuilder.security.manager import AUTH_OID
from superset.security import SupersetSecurityManager
from flask_oidc import OpenIDConnect
from flask_appbuilder.security.views import AuthOIDView
from flask_login import login_user
from urllib.parse import quote
from flask_appbuilder.views import expose
from flask import request, redirect
class OIDCSecurityManager(SupersetSecurityManager):
def __init__(self, appbuilder):
super(OIDCSecurityManager, self).__init__(appbuilder)
if self.auth_type == AUTH_OID:
self.oid = OpenIDConnect(self.appbuilder.get_app)
self.authoidview = AuthOIDCView
class AuthOIDCView(AuthOIDView):
@expose('/login/', methods=['GET', 'POST'])
def login(self, flag=True):
sm = self.appbuilder.sm
oidc = sm.oid
superset_roles = ["Admin", "Alpha", "Gamma", "Public", "granter", "sql_lab"]
default_role = "Gamma"
@self.appbuilder.sm.oid.require_login
def handle_login():
user = sm.auth_user_oid(oidc.user_getfield('email'))
if user is None:
info = oidc.user_getinfo(['preferred_username', 'given_name', 'family_name', 'email', 'roles'])
roles = [role for role in superset_roles if role in info.get('roles', [])]
roles += [default_role, ] if not roles else []
user = sm.add_user(info.get('preferred_username'), info.get('given_name', ''), info.get('family_name', ''),
info.get('email'), [sm.find_role(role) for role in roles])
login_user(user, remember=False)
return redirect(self.appbuilder.get_url_for_index)
return handle_login()
@expose('/logout/', methods=['GET', 'POST'])
def logout(self):
oidc = self.appbuilder.sm.oid
oidc.logout()
super(AuthOIDCView, self).logout()
redirect_url = request.url_root.strip('/')
# redirect_url = request.url_root.strip('/') + self.appbuilder.get_url_for_login
return redirect(
oidc.client_secrets.get('issuer') + '/protocol/openid-connect/logout?redirect_uri=' + quote(redirect_url))
6. Bootstrap Script
Values.extraSecrets.bootstrapScirpt
#!/bin/bash
rm -rf /var/lib/apt/lists/* && \
pip install \
psycopg2-binary==2.9.1 \
itsdangerous==2.0.1 \
flask-oidc==1.4.0 \
Flask-OpenID==1.3.0 \
redis==3.5.3 && \
if [ ! -f ~/bootstrap ]; then echo "Running Superset with uid {{ .Values.runAsUser }}" > ~/bootstrap; fi
7. Optionally if you are using ingress controller & cert-manager
ingress:
annotations:
nginx.ingress.kubernetes.io/client-body-buffer-size: 10M
nginx.ingress.kubernetes.io/proxy-body-size: 10M
nginx.ingress.kubernetes.io/proxy-buffering: "on"
nginx.ingress.kubernetes.io/proxy-buffer-size: "10M"
nginx.ingress.kubernetes.io/proxy-buffers-number: "4"
enabled: true
ingressClassName: nginx
path: /
pathType: ImplementationSpecific
hosts:
- <YOUR_HOST_NAME>
tls:
- secretName: <TLS_SECRET_NAME>
hosts:
- <YOUR_HOST_NAME>
Run the chart
1. Create a database in Postgres instance
kubectl port-forward service/<SERVICE_NAME_OF_POSTGRES> 5432
createdb -h 127.0.0.1 -p 5432 -U <USERNAME> superset
2. After replacing all values run this command
helm upgrade --install superset superset-keycloak -f superset-keycloak/keycloak-values.yaml --namespace superset --create-namespace
Conclusion
This way we can now authenticate Apache superset with Keycloak with OIDC protocols.
For more interesting blogs checkout Knoldus blogs site