首页 > 解决方案 > 使用 dex (oauth / openid connect) 连接到超集并将 dex 组映射到角色

问题描述

我一直在广泛查看文档和 stackover 流程​​,以获取有关如何使用 helm chart 进行此设置的示例。

我一直在努力让 OAuth 和组角色映射正常工作

OAUTH_PROVIDERS = [
{   'name':'egaSSO',
    'token_key':'access_token', # Name of the token in the response of access_token_url
    'icon':'fa-address-card',   # Icon for the provider
    'remote_app': {
        'client_id':'myClientId',  # Client Id (Identify Superset application)
        'client_secret':'MySecret', # Secret for this Client Id (Identify Superset application)
        'server_metadata_url': 'https://myAuthorizationServer/.well-known/openid-configuration'
    }
}
]

此示例配置在将用户信息响应从 dex 映射到登录时不起作用。

标签: python-3.xkubernetes-helmflask-loginapache-superset

解决方案


我已经建立了自己的答案 https://gist.github.com/nelaaro/a2ef6f2a268d5a8a7caf6676e2ef2bb5

我只显示对我有用的相关部分这就是我的values.yaml

# Install additional packages and do any other bootstrap configuration in this script
# For production clusters it's recommended to build own image with this step done in CI
bootstrapScript: |
#!/bin/bash
rm -rf /var/lib/apt/lists/* && \
pip install \
    psycopg2==2.8.5 \
    redis==3.2.1  \
    thrift \
    sasl \
    thrift_sasl \
    pyhive \
    elasticsearch-dbapi \
    Authlib \
    JMESPath \
    sqlalchemy-trino && \
if [ ! -f ~/bootstrap ]; then echo "Running Superset with uid {{ .Values.runAsUser }}" > ~/bootstrap; fi
extraSecrets:
custom_sso_security_manager.py: |-
    import logging
    from superset.security import SupersetSecurityManager
    class CustomSsoSecurityManager(SupersetSecurityManager):
        def oauth_user_info(self, provider, response=None):
            userinfo = {}
            logging.debug("Oauth2 provider: {0}.".format(provider))
            if provider == 'dex':
                # As example, this line request a GET to base_url + '/' + userDetails with Bearer  Authentication,
                # and expects that authorization server checks the token, and response with user details
                me = self.appbuilder.sm.oauth_remotes[provider].get('userinfo').json()
                # logging.debug("user_data me: {0}".format(me))
                # logging.debug("user_data me[name]: {0}".format(me['name']))
                # logging.debug("user_data me[groups]: {0}".format(me['groups']))
                role_map = {'datascience': 'Gamma',
                'data-engineering': 'Alpha',
                'data-platform-admin': 'Admin'}
                roles = [role_map[key] for key in me['groups'] if key in role_map]
                logging.debug("user_data roles: {0}".format(roles))
                userinfo = {
                'name' : me['name'],
                'email' : me['email'],
                'id' : me['preferred_username'],
                'username' : me['preferred_username'],
                'first_name': me['name'].split()[0],
                'last_name': me['name'].split()[-1],
                'groups': me['groups'],
                'role_keys': roles
                }
                logging.debug("user_info: {0}".format(userinfo))
                return userinfo
            else:
                return userinfo

# A dictionary of overrides to append at the end of superset_config.py - the name does not matter
# WARNING: the order is not guaranteed
configOverrides:

a_override_proxy: |
    # https://superset.apache.org/docs/installation/running-on-kubernetes#superset_configpy
    # This will make sure the redirect_uri is properly computed, even with SSL offloading
    ENABLE_PROXY_FIX = True
    FEATURE_FLAGS = {
        "DYNAMIC_PLUGINS": True
    }
# https://stackoverflow.com/questions/47678321/using-openid-keycloak-with-superset
# https://stackoverflow.com/questions/54010314/using-keycloakopenid-connect-with-apache-superset
# https://superset.apache.org/docs/installation/configuring-superset
# https://flask-appbuilder.readthedocs.io/en/latest/security.html#authentication-oauth
# https://flask-appbuilder.readthedocs.io/en/latest/config.html full config reference
# https://docs.authlib.org/en/latest/client/flask.html
# https://github.com/apache/superset/issues/13806
enable_oauth: |
    from flask_appbuilder.security.manager import (AUTH_DB, AUTH_OAUTH, AUTH_OID)
    from custom_sso_security_manager import CustomSsoSecurityManager
    CUSTOM_SECURITY_MANAGER = CustomSsoSecurityManager
    AUTH_TYPE = AUTH_OAUTH
    OAUTH_PROVIDERS = [
        {   "name":"dex",
            "token_key":"access_token", # Name of the token in the response of access_token_url
            "icon":"fa-address-card",   # Icon for the provider
            "remote_app": {
                "client_id":"superset-auth",  # Client Id (Identify Superset application)
                "client_secret":"some lone secure secret", # Secret for this Client Id (Identify Superset application)
                "server_metadata_url": "https://dex.somedomain.net/.well-known/openid-configuration",
                "api_base_url": "https://dex.somedomain.net/", # required for the custom security manager to work CUSTOM_SECURITY_MANAGER
                # "access_token_url": "https://dex.somedomain.net/token",
                # "authorize_url": "https://dex.somedomain.net/auth",
                # "redirect_uri":"https://superset.somedomain.net/oauth-authorized/dex",
                "client_kwargs":{
                    "scope": "openid profile email groups"      # Scope for the Authorization
                }
            }
        }
    ]
    # Will allow user self registration, allowing to create Flask users from Authorized User
    AUTH_USER_REGISTRATION = True
    PUBLIC_ROLE_LIKE = "Gamma" # allow access to dashboard for users not logged in.
    # Map Authlib roles to superset roles
    # AUTH_ROLE_ADMIN = "Admin"
    AUTH_ROLE_PUBLIC = "Public"
    # The default user self registration role or use AUTH_USER_REGISTRATION_ROLE_JMESPATH below
    # AUTH_USER_REGISTRATION_ROLE = "Admin"
    # AUTH_USER_REGISTRATION_ROLE = "Public"
    # if we should replace ALL the user's roles each login, or only on registration
    AUTH_ROLES_SYNC_AT_LOGIN = True
    # https://flask-appbuilder.readthedocs.io/en/latest/config.html#jmespath-examples
    # https://flask-appbuilder.readthedocs.io/en/latest/security.html#role-based
    # https://apache.github.io/superset/security.html
    # https://api.gopipeline.io/jmespath-tester
    AUTH_USER_REGISTRATION_ROLE_JMESPATH = "sort(role_keys)[0] || 'Gamma'"

这里重要的是角色如何映射到超集使用的角色。

AUTH_USER_REGISTRATION_ROLE_JMESPATH = "sort(role_keys)[0] || 'Gamma'"

上述工作是因为我在我的 dex oauth 响应中发送我的 ldap 组。

role_map = {'datascience': 'Gamma',
'data-engineering': 'Alpha',
'data-platform-admin': 'Admin'}
roles = [role_map[key] for key in me['groups'] if key in role_map]

推荐阅读