如何用Keycloak设置Apache Superset

598 阅读2分钟

在这篇博客中,我们将学习如何部署和设置带有Keycloak认证的Apache SupersetApache Superset是一个用于数据探索和数据可视化的开源软件,能够处理PB级的数据。Keycloak是一个开源的软件产品,允许使用身份和访问管理的单点登录,旨在为现代应用程序和服务。

前提条件

  • Keycloak服务器
    • Keycloak境界
    • 使用OIDC协议配置的Keycloak客户端和代理。
    • client_secret.json
  • 一个部署在同一Kubernetes集群上的PostgreSQL实例
  • 系统中安装了Helm,并有Helm的基本知识。
  • PostgreSQL实例的管理员用户名和密码
  • 在PostgreSQL中创建的超级数据库(如果没有,请遵循步骤3)
  • 如果你想在主机名上设置SSL证书,可以选择Cert-manager。

在你开始之前

1 克隆这个Repo的脚本

git clone https://github.com/knoldus/apache-superset-with-keycloak.git

2 更改目录到克隆的Repo中

cd apache-superset-with-keycloak

设置步骤

1.为你的客户认证生成client_secret.json文件

该文件的内容应该是这样的。用你的值来改变和替换

{
    "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"
    }
}

用这个命令将JSON文件扁平化

cat client_secret.json|tr -d "\n"

2.在.Values.extraSecrets.client_secret.json文件中替换复制的扁平化内容。

extraSecrets:
  client_secret.json: |
    <YOUR_CLIENT_SECRET_JSON_STRING>

3.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.添加keycloak的境界名称

extraEnv:
  OIDC_OPENID_REALM: <YOUR_REALM_NAME>

5.keycloak-values.yaml中的keycloak_security_manager.py脚本

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脚本

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.如果你正在使用ingress控制器和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>

运行图表

1.在Postgres实例中创建一个数据库

kubectl port-forward service/<SERVICE_NAME_OF_POSTGRES> 5432
createdb -h 127.0.0.1 -p 5432 -U <USERNAME> superset

2.替换所有数值后,运行这个命令

helm upgrade --install superset superset-keycloak -f superset-keycloak/keycloak-values.yaml --namespace superset --create-namespace

结论

这样我们就可以用Keycloak和OIDC协议来验证Apache superset了。