Aller au contenu

SSO Entra ID (OAuth) sur Superset — Ouranos

Objectif

Permettre aux utilisateurs de se connecter a Superset via leur compte Microsoft Entra ID (Azure AD) en OAuth. L'authentification est geree directement entre Superset et Entra ID — Cloudflare tunnel sert uniquement de transport securise.

Architecture

Utilisateur
    |
    v
[superset.oxyane-na.fr] (Cloudflare tunnel)
    |
    v
[Superset — page login]
    |
    └── Bouton "Sign in with Azure"
            |
            v
        [Entra ID — login SSO + MFA]
            |
            v
        [Callback → /oauth-authorized/azure]
            |
            v
        [Superset — utilisateur connecte]

Pourquoi OAuth et pas REMOTE_USER ?

L'approche AUTH_REMOTE_USER (header Cloudflare Access) ne fonctionne pas avec les versions recentes de Superset (bug LocalProxy is not mapped). L'approche OAuth est native, stable, et geree directement par Flask-AppBuilder.

Prerequis

  • Superset deploye et accessible via superset.oxyane-na.fr
  • Un tenant Microsoft Entra ID (Azure AD)
  • Acces admin au portail Entra : https://entra.microsoft.com/

Etape 1 — Enregistrer l'application dans Entra ID

Creer l'app registration

  1. Aller sur https://entra.microsoft.com/
  2. IdentityApplicationsApp registrationsNew registration
  3. Remplir :
Champ Valeur
Name Superset Ouranos
Supported account types Accounts in this organizational directory only
Redirect URI (Web) https://superset.oxyane-na.fr/oauth-authorized/azure
  1. Register

Noter les identifiants

Sur la page de l'application creee, noter :

Valeur Ou la trouver
Application (client) ID Overview → Application (client) ID
Directory (tenant) ID Overview → Directory (tenant) ID

Creer un client secret

  1. Certificates & secretsClient secretsNew client secret
  2. Description : Superset OAuth
  3. Expiration : 24 months (ou selon votre politique)
  4. Add
  5. Copier immediatement la Value (elle ne sera plus visible apres)
Valeur Ou la trouver
Client secret (Value) Certificates & secrets → Value (copier immediatement)

Configurer les permissions API

  1. API permissionsAdd a permission
  2. Microsoft GraphDelegated permissions
  3. Cocher :
  4. openid
  5. profile
  6. email
  7. User.Read
  8. Add permissions
  9. Grant admin consent (bouton en haut)

Etape 2 — Variables d'environnement Portainer

Ajouter ces 3 variables dans la stack Superset (Portainer → Stack superset → Environment variables) :

Variable Valeur
AZURE_CLIENT_ID Application (client) ID copie a l'etape 1
AZURE_CLIENT_SECRET Client secret Value copie a l'etape 1
AZURE_TENANT_ID Directory (tenant) ID copie a l'etape 1

Etape 3 — Modifier superset_config.py

Sur le VPS Ouranos (SSH ou terminal Cockpit).

Ne pas utiliser de heredoc bash

Le fichier contient des f-strings Python et des classes. Les heredoc bash peuvent casser la syntaxe. Utiliser le script d'installation fourni ou editer avec sudo nano.

Telecharger et executer le script d'installation :

# Telecharger install-superset-config.sh (fourni en piece jointe)
# Puis executer :
sudo bash install-superset-config.sh

Ou editer manuellement :

sudo nano /opt/superset-config/superset_config.py

Le contenu du fichier superset_config.py :

import os
from flask_appbuilder.security.manager import AUTH_OAUTH
from superset.security import SupersetSecurityManager

SECRET_KEY = os.environ.get("SUPERSET_SECRET_KEY", "CHANGE_ME")

SQLALCHEMY_DATABASE_URI = (
    f"postgresql+psycopg2://"
    f"{os.environ.get('DATABASE_USER', 'superset')}:"
    f"{os.environ.get('DATABASE_PASSWORD', 'superset')}@"
    f"{os.environ.get('DATABASE_HOST', 'superset-db')}:"
    f"{os.environ.get('DATABASE_PORT', '5432')}/"
    f"{os.environ.get('DATABASE_DB', 'superset')}"
)

class CeleryConfig:
    broker_url = f"redis://{os.environ.get('REDIS_HOST', 'superset-redis')}:{os.environ.get('REDIS_PORT', '6379')}/0"
    result_backend = f"redis://{os.environ.get('REDIS_HOST', 'superset-redis')}:{os.environ.get('REDIS_PORT', '6379')}/0"

CELERY_CONFIG = CeleryConfig
MAPBOX_API_KEY = os.environ.get("MAPBOX_API_KEY", "")
WTF_CSRF_ENABLED = True
ENABLE_PROXY_FIX = True
RECAPTCHA_PUBLIC_KEY = ""

BABEL_DEFAULT_LOCALE = "fr"
LANGUAGES = {
    "fr": {"flag": "fr", "name": "Francais"},
    "en": {"flag": "us", "name": "English"},
}

AUTH_TYPE = AUTH_OAUTH
AUTH_USER_REGISTRATION = True
AUTH_USER_REGISTRATION_ROLE = "Gamma"

OAUTH_PROVIDERS = [
    {
        "name": "azure",
        "icon": "fa-windows",
        "token_key": "access_token",
        "remote_app": {
            "client_id": os.environ.get("AZURE_CLIENT_ID", ""),
            "client_secret": os.environ.get("AZURE_CLIENT_SECRET", ""),
            "api_base_url": "https://graph.microsoft.com/v1.0/",
            "client_kwargs": {
                "scope": "User.Read openid profile email",
            },
            "access_token_url": f"https://login.microsoftonline.com/{os.environ.get('AZURE_TENANT_ID', '')}/oauth2/v2.0/token",
            "authorize_url": f"https://login.microsoftonline.com/{os.environ.get('AZURE_TENANT_ID', '')}/oauth2/v2.0/authorize",
            "server_metadata_url": f"https://login.microsoftonline.com/{os.environ.get('AZURE_TENANT_ID', '')}/v2.0/.well-known/openid-configuration",
        },
    }
]

class CustomSecurityManager(SupersetSecurityManager):
    def oauth_user_info(self, provider, response=None):
        if provider == "azure":
            me = self.appbuilder.sm.oauth_remotes[provider].get("me")
            data = me.json()
            return {
                "username": data.get("mail", data.get("userPrincipalName", "")),
                "email": data.get("mail", data.get("userPrincipalName", "")),
                "first_name": data.get("givenName", ""),
                "last_name": data.get("surname", ""),
            }
        return {}

CUSTOM_SECURITY_MANAGER = CustomSecurityManager

CustomSecurityManager

Sans ce custom manager, Entra envoie un UUID comme username au lieu de l'email. Le oauth_user_info interroge Microsoft Graph (/me) pour recuperer l'email, le prenom et le nom.


Etape 4 — Compose avec authlib

Dependance authlib requise

L'image apache/superset:latest-dev n'inclut pas le module authlib necessaire pour OAuth. Le compose doit installer authlib au demarrage de chaque conteneur Superset.

Le compose doit inclure /app/.venv/bin/pip install authlib dans les commandes de superset-init, superset-app et superset-worker. Voir le fichier docker-compose-superset-oauth.yml dans la documentation de deploiement.

Etape 5 — Redemarrer Superset

sudo docker restart superset_app superset_worker

Verifier les logs :

sudo docker logs superset_app --tail=20

Doit afficher Listening at: http://0.0.0.0:8088 sans erreur.


Etape 5 — Tester le SSO

Test en navigation privee

  1. Ouvrir une fenetre navigation privee
  2. Aller sur https://superset.oxyane-na.fr
  3. La page de login Superset affiche un bouton "Sign in with Azure"
  4. Cliquer dessus
  5. Entra ID demande le login (+ MFA si configure)
  6. Apres authentification → retour sur Superset, connecte automatiquement

Verification de l'utilisateur cree

  1. Se connecter en admin
  2. SettingsList Users
  3. L'utilisateur SSO apparait avec :
  4. Username : son email Entra
  5. Role : Gamma (par defaut)

Etape 6 — Promouvoir un utilisateur SSO en Admin

Les utilisateurs crees par SSO ont le role Gamma (lecture seule). Pour promouvoir un utilisateur en Admin :

Si un admin existe deja dans Superset

  1. Se connecter avec le compte admin
  2. SettingsList Users → cliquer sur l'utilisateur → modifier le RoleAdminSave

Si aucun admin n'existe (premier setup)

Promouvoir directement en base de donnees :

sudo docker exec -it superset_db psql -U superset -d superset -c "
INSERT INTO ab_user_role (id, user_id, role_id)
SELECT nextval('ab_user_role_id_seq'), u.id, r.id
FROM ab_user u, ab_role r
WHERE u.email = 'ton.email@domaine.fr' AND r.name = 'Admin';
"

Remplacer ton.email@domaine.fr par l'email Entra de l'utilisateur a promouvoir.

Puis rafraichir la page Superset — le menu Settings apparait.


Etape 7 — Row-Level Security (cloisonnement)

Le RLS fonctionne avec OAuth : la clause de filtre s'applique selon le role de l'utilisateur connecte via Entra.

  1. SettingsRow Level Security+ Rule
  2. Tables : ta vue PostgreSQL
  3. Roles : le role de l'utilisateur (ex: "Commercial Dupont")
  4. Clause : societe = 'Dupont'

L'utilisateur ne voit que ses donnees sur les cartes et dashboards.


Acces de secours (si Entra tombe)

Si Entra ID est en panne, le bouton "Sign in with Azure" ne fonctionne plus.

Methode 1 — Login admin local

Le compte admin local (Admin / mot de passe) reste utilisable meme avec OAuth. Sur la page de login, les champs username/password sont toujours presents a cote du bouton Azure.

Methode 2 — Tunnel SSH direct

ssh -L 8088:localhost:8088 debian@51.77.150.97
# Ouvrir http://localhost:8088
# Se connecter avec le compte admin local

Methode 3 — Desactiver temporairement OAuth

sudo sed -i 's/AUTH_TYPE = AUTH_OAUTH/AUTH_TYPE = 1/' /opt/superset-config/superset_config.py
sudo docker restart superset_app

Depannage

Probleme Cause probable Solution
"Sign in with Azure" n'apparait pas AUTH_TYPE n'est pas AUTH_OAUTH Verifier le config + redemarrer
"AADSTS50011: Reply URL does not match" Redirect URI incorrect dans Entra Verifier : https://superset.oxyane-na.fr/oauth-authorized/azure
"AADSTS7000215: Invalid client secret" Secret expire ou mal copie Recreer le secret dans Entra + mettre a jour la variable Portainer
"AADSTS700016: Application not found" Client ID incorrect Verifier AZURE_CLIENT_ID dans Portainer
Utilisateur connecte mais erreur 500 RECAPTCHA_PUBLIC_KEY manquant Ajouter RECAPTCHA_PUBLIC_KEY = "" dans le config
Utilisateur cree avec mauvais role Role par defaut = Gamma Promouvoir via Settings ou SQL (voir etape 6)
"KeyError: RECAPTCHA_PUBLIC_KEY" Bug version latest-dev Ajouter la ligne dans le config
"No module named authlib" authlib pas installe dans le venv Verifier que le compose inclut /app/.venv/bin/pip install authlib
"duplicate key email" au login SSO Compte cree manuellement avec le meme email Supprimer : sudo docker exec -it superset_db psql -U superset -d superset -c "DELETE FROM ab_user WHERE email = 'xxx';"
Username = UUID au lieu de email Pas de CustomSecurityManager Verifier que CUSTOM_SECURITY_MANAGER = CustomSecurityManager est dans le config
SyntaxError dans superset_config.py Commentaires sans # ou heredoc bash corrompu Utiliser le script install-superset-config.sh ou editer avec sudo nano
"Login invalide" apres Azure OAuth echoue silencieusement Verifier les logs : sudo docker logs superset_app --tail=30

Variables d'environnement — Recapitulatif

Variable Stack Portainer Description
SUPERSET_SECRET_KEY superset Cle de chiffrement
SUPERSET_DB_PASSWORD superset Mot de passe BDD interne
SUPERSET_ADMIN_PASSWORD superset Mot de passe admin local
SUPERSET_ADMIN_EMAIL superset Email admin local
MAPBOX_TOKEN superset Token Mapbox (cartes)
AZURE_CLIENT_ID superset App registration Entra
AZURE_CLIENT_SECRET superset Secret Entra
AZURE_TENANT_ID superset Tenant Entra

Voir aussi