Partager via


Exposer Apache Superset à Internet

Cet article explique comment exposer Apache Superset à Internet.

Sélection du nom d’hôte

  1. Choisissez un nom d’hôte pour Superset.

    Sauf si vous utilisez un nom DNS personnalisé, ce nom d’hôte doit correspondre au modèle : <superset-instance-name>.<azure-region>.cloudapp.azure.com. L'instance de superset doit être unique dans la région Azure.

    Exemple : myuniquesuperset.westus3.cloudapp.azure.com

  2. Obtenez un certificat TLS pour le nom d’hôte et placez-le dans votre coffre de clés et appelez-le aks-ingress-tls. Découvrez comment placer un certificat dans un Azure Key Vault.

Configuration de l'ingress

Les instructions suivantes ajoutent une deuxième couche d’authentification sous la forme d’un proxy d’autorisation OAuth à l’aide d’Oauth2Proxy. Cette couche signifie qu’aucun client non autorisé n’atteint l’application Superset.

  1. Ajoutez les secrets suivants à votre coffre de clés.

    Nom du secret Description
    identifiant-client Identifiant client de votre service principal Azure. Le proxy OAuth nécessite que cet ID soit un secret.
    oauth2proxy-redis-password Mot de passe du cache du proxy. Mot de passe utilisé par le proxy OAuth pour accéder à l’instance de déploiement Redis principale sur Kubernetes. Générez un mot de passe fort.
    oauth2proxy-cookie-secret Secret de cookie de 32 caractères, utilisé pour chiffrer les données de cookie. Ce secret doit contenir 32 caractères.
  2. Ajoutez ces rappels dans votre configuration d’application Azure AD Superset.

    • https://{{superset_hostname}}/oauth2/callback
      • pour le proxy OAuth2
    • https://{{superset_hostname}}/oauth-authorized/azure
      • pour Superset
  3. Déployer le contrôleur d'ingress nginx dans le namespace default

    helm install ingress-nginx-superset ingress-nginx/ingress-nginx \
    --namespace default \
    --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-health-probe-request-path"=/healthz \
    --set controller.config.proxy-connect-timeout="60" \
    --set controller.config.proxy-read-timeout="1000" \
    --set controller.config.proxy-send-timeout="1000" \
    --set controller.config.proxy-buffer-size="'64k'" \
    --set controller.config.proxy-buffers-number="8"
    

    Pour obtenir des instructions détaillées, consultez instructions Azure ici.

    Note

    Les étapes du contrôleur nginx d’entrée utilisent l’espace de noms Kubernetes ingress-basic. Cette opération doit être modifiée à l’aide de l’espace de noms default. par exemple, NAMESPACE=default

  4. Créez une classe de fournisseur de secrets TLS.

    Cette étape décrit comment le certificat TLS est lu à partir du coffre de clés et transformé en secret Kubernetes à utiliser par l’entrée :

    Mettez à jour dans le yaml suivant :

    • {{MSI_CLIENT_ID}} - ID client de l’identité managée affectée au cluster Superset ($MANAGED_IDENTITY_RESOURCE).
    • {{KEY_VAULT_NAME}} : nom du coffre de clés Azure contenant les secrets.
    • {{KEY_VAULT_TENANT_ID}} - L'identifiant GUID du locataire d'Azure où se trouve le Key Vault.

    tls-secretprovider.yaml

    apiVersion: secrets-store.csi.x-k8s.io/v1
    kind: SecretProviderClass
    metadata:
      name: azure-tls
    spec:
      provider: azure
      # secretObjects defines the desired state of synced K8s secret objects
      secretObjects:
      - secretName: ingress-tls-csi
        type: kubernetes.io/tls
        data: 
        - objectName: aks-ingress-tls
          key: tls.key
        - objectName: aks-ingress-tls
          key: tls.crt
      parameters:
        usePodIdentity: "false"
        useVMManagedIdentity: "true"
        userAssignedIdentityID: "{{MSI_CLIENT_ID}}"
        # the name of the AKV instance
        keyvaultName: "{{KEY_VAULT_NAME}}"
        objects: |
          array:
            - |
              objectName: aks-ingress-tls
              objectType: secret
        # the tenant ID of the AKV instance
        tenantId: "{{KEY_VAULT_TENANT_ID}}"
    
  5. Créez une classe de fournisseur secret OauthProxy.

    Mettez à jour dans le yaml suivant :

    • {{MSI_CLIENT_ID}} - ID client de l’identité managée affectée au cluster Superset ($MANAGED_IDENTITY_RESOURCE).
    • {{KEY_VAULT_NAME}} : nom du coffre de clés Azure contenant les secrets.
    • {{KEY_VAULT_TENANT_ID}} - L'identifiant GUID du locataire Azure où se trouve le Coffre de clés.

    oauth2-secretprovider.yaml

    # This is a SecretProviderClass example using aad-pod-identity to access the key vault
    apiVersion: secrets-store.csi.x-k8s.io/v1
    kind: SecretProviderClass
    metadata:
      name: oauth2-secret-provider
    spec:
      provider: azure
      parameters:
        useVMManagedIdentity: "true" 
        userAssignedIdentityID: "{{MSI_CLIENT_ID}}"
        usePodIdentity: "false"              # Set to true for using aad-pod-identity to access your key vault
        keyvaultName: "{{KEY_VAULT_NAME}}"   # Set to the name of your key vault
        cloudName: ""                        # [OPTIONAL for Azure] if not provided, the Azure environment defaults to AzurePublicCloud
        objects: |
          array:
            - |
              objectName: oauth2proxy-cookie-secret
              objectType: secret
            - |
              objectName: oauth2proxy-redis-password
              objectType: secret
            - |
              objectName: client-id
              objectType: secret
            - |
              objectName: client-secret
              objectType: secret
        tenantId: "{{KEY_VAULT_TENANT_ID}}"  # The tenant ID of the key vault
      secretObjects:                             
      - secretName: oauth2-secret
        type: Opaque
        data:
        # OauthProxy2 Secrets
        - key: cookie-secret
          objectName: oauth2proxy-cookie-secret
        - key: client-id
          objectName: client-id
        - key: client-secret
          objectName: client-secret
        - key: redis-password
          objectName: oauth2proxy-redis-password
      - secretName: oauth2-redis
        type: Opaque
        data:
        - key: redis-password
          objectName: oauth2proxy-redis-password
    
  6. Créez une configuration pour le proxy OAuth.

    Mettez à jour dans le yaml suivant :

    • {{superset_hostname}} : nom d’hôte à destination d'Internet sélectionné lors de la sélection de nom d’hôte
    • {{tenant-id}} - GUID d'identificateur du client Azure où votre entité de service a été créée.

    Facultatif : mettre à jour la liste des domaines_de_courriel. Exemple : email_domains = [ "microsoft.com" ]

    oauth2-values.yaml

    # Force the target Kubernetes version (it uses Helm `.Capabilities` if not set).
    # This is especially useful for `helm template` as capabilities are always empty
    # due to the fact that it doesn't query an actual cluster
    kubeVersion:
    
    # OAuth client configuration specifics
    config:
      # OAuth client secret
      existingSecret: oauth2-secret
      configFile: |-
        email_domains = [ ]
        upstreams = [ "file:///dev/null" ]
    
    image:
      repository: "quay.io/oauth2-proxy/oauth2-proxy"
      tag: "v7.4.0"
      pullPolicy: "IfNotPresent"
    
    extraArgs: 
        provider: oidc
        oidc-issuer-url: https://login.microsoftonline.com/<tenant-id>/v2.0
        login-url: https://login.microsoftonline.com/<tenant-id>/v2.0/oauth2/authorize
        redeem-url: https://login.microsoftonline.com/<tenant-id>/v2.0/oauth2/token
        oidc-jwks-url: https://login.microsoftonline.com/common/discovery/keys
        profile-url: https://graph.microsoft.com/v1.0/me
        skip-provider-button: true
    
    ingress:
      enabled: true
      path: /oauth2
      pathType: ImplementationSpecific
      hosts:
      - "{{superset_hostname}}"
      annotations:
        kubernetes.io/ingress.class: nginx
        nginx.ingress.kubernetes.io/proxy_buffer_size: 64k
        nginx.ingress.kubernetes.io/proxy_buffers_number: "8"
      tls:
      - secretName: ingress-tls-csi
        hosts:
         - "{{superset_hostname}}"
    
    extraVolumes:
      - name: oauth2-secrets-store
        csi:
          driver: secrets-store.csi.k8s.io
          readOnly: true
          volumeAttributes:
            secretProviderClass: oauth2-secret-provider
      - name: tls-secrets-store
        csi:
          driver: secrets-store.csi.k8s.io
          readOnly: true
          volumeAttributes:
            secretProviderClass: azure-tls
    
    extraVolumeMounts: 
      - mountPath: "/mnt/oauth2_secrets"
        name: oauth2-secrets-store
        readOnly: true
      - mountPath: "/mnt/tls-secrets-store"
        name: tls-secrets-store
        readOnly: true
    
    # Configure the session storage type, between cookie and redis
    sessionStorage:
      # Can be one of the supported session storage cookie/redis
      type: redis
      redis:
        # Secret name that holds the redis-password and redis-sentinel-password values
        existingSecret: oauth2-secret
        # Can be one of sentinel/cluster/standalone
        clientType: "standalone"
    
    # Enables and configure the automatic deployment of the redis subchart
    redis:
      enabled: true
      auth:
        existingSecret: oauth2-secret
    
    # Enables apiVersion deprecation checks
    checkDeprecation: true
    
  7. Déployez des ressources proxy OAuth.

    kubectl apply -f oauth2-secretprovider.yaml
    kubectl apply -f tls-secretprovider.yaml
    helm repo add oauth2-proxy https://oauth2-proxy.github.io/manifests
    helm repo update
    helm upgrade --install --values oauth2-values.yaml oauth2 oauth2-proxy/oauth2-proxy
    
  8. Mettez à jour l’étiquette DNS dans l’adresse IP publique associée.

    1. Ouvrez votre cluster Kubernetes AKS Superset dans le portail Azure.

    2. Sélectionnez « Propriétés » dans le volet de navigation gauche.

    3. Ouvrez le lien « Groupe de ressources d’infrastructure ».

    4. Recherchez l’adresse IP publique avec ces balises :

      {
        "k8s-azure-cluster-name": "kubernetes",
        "k8s-azure-service": "default/ingress-nginx-controller"
      }
      
    5. Sélectionnez « Configuration » depuis le menu de navigation de gauche sous IP publique.

    6. Entrez l'étiquette de nom DNS définie avec la <superset-instance-name> dans la sélection de nom d'hôte .

  9. Vérifiez que votre entrée pour OAuth est configurée.

    Exécutez kubectl get ingress pour voir les deux ingresses créées azure-trino-superset et oauth2-oauth2-proxy. L’adresse IP correspond à l’adresse IP publique de l’étape précédente.

    De même, lorsque vous exécutez kubectl get services vous devez voir que ingress-nginx-controller a été affecté à un EXTERNAL-IP.

    Pourboire

    Vous pouvez ouvrir http://{{superset_hostname}}/oauth2 pour tester que le chemin OAuth fonctionne.

  10. Définissez une entrée pour fournir l’accès à Superset, mais redirigez tous les appels non autorisés vers /oauth.

    Mettez à jour dans le yaml suivant :

    • {{superset_hostname}} : nom d’hôte à destination d'Internet sélectionné lors de la sélection de nom d’hôte

    ingress.yaml

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      annotations:
        kubernetes.io/ingress.class: nginx
        nginx.ingress.kubernetes.io/auth-signin: https://$host/oauth2/start?rd=$escaped_request_uri
        nginx.ingress.kubernetes.io/auth-url: http://oauth2-oauth2-proxy.default.svc.cluster.local:80/oauth2/auth
        nginx.ingress.kubernetes.io/proxy-buffer-size: 64k
        nginx.ingress.kubernetes.io/proxy-buffers-number: "8"
        nginx.ingress.kubernetes.io/rewrite-target: /$1
      generation: 1
      labels:
        app.kubernetes.io/name: azure-trino-superset
      name: azure-trino-superset
      namespace: default
    spec:
      rules:
      - host: "{{superset_hostname}}"
        http:
          paths:
          - backend:
              service:
                name: superset
                port:
                  number: 8088
            path: /(.*)
            pathType: Prefix
      tls:
      - hosts:
        - "{{superset_hostname}}"
        secretName: ingress-tls-csi
    
  11. Déployez votre point d'entrée.

          kubectl apply -f ingress.yaml
    
  12. Test.

    Ouvrez https://{{superset_hostname}}/ dans votre navigateur.

Résolution des problèmes d’entrée

Pourboire

Pour réinitialiser le déploiement d’entrée, exécutez ces commandes :

kubectl delete secret ingress-tls-csi
kubectl delete secret oauth2-secret
helm uninstall oauth2-proxy
helm uninstall ingress-nginx-superset
kubectl delete ingress azure-trino-superset

Après avoir supprimé ces ressources, vous devez redémarrer ces instructions à partir du début.

Certificat de sécurité non valide : Faux certificat du contrôleur d’entrée Kubernetes

Cela provoque une erreur de vérification de certificat TLS dans votre navigateur/client. Pour voir cette erreur, inspectez le certificat dans un navigateur.

La cause habituelle de ce problème est que votre certificat est mal configuré :

  • Vérifiez que vous pouvez voir votre certificat dans Kubernetes : kubectl get secret ingress-tls-csi --output yaml

  • Vérifiez que votre CN correspond au CN fourni dans votre certificat.

    • L’incompatibilité CN est enregistrée dans le pod d’entrée. Ces journaux d’activité sont visibles en exécutant kubectl logs <ingress pod>.

      Exemple : kubectl logs ingress-nginx-superset-controller-f5dd9ccfd-qz8wc

    L’erreur d’incompatibilité CN est décrite avec cette ligne de journal (log) :

    Le certificat SSL « default/ingress-tls-csi » ne contient pas de nom commun ou d’autre nom d’objet pour le serveur « {nom de serveur} » : x509 : le certificat est valide pour {nom d’hôte non valide}, et non {nom d’hôte réel}

Impossible de résoudre l’hôte

Si le nom d’hôte ne peut pas être résolu pour l’instance Superset, l’adresse IP publique n’a pas de nom d’hôte affecté. Sans cette attribution, DNS ne peut pas résoudre le nom d’hôte.

Vérifiez les étapes de la section Mettre à jour l’étiquette DNS dans l’adresse IP publique associée.

404 / nginx

Le contrôleur d’entrée Nginx ne trouve pas le Superset. Assurez-vous que Superset est déployé en exécutant kubectl get services et en vérifiant la présence d’un service superset. Vérifiez que le service principal dans ingress.yaml correspond au nom de service utilisé pour Superset.

503 Service temporairement indisponible / nginx

Le service est en cours d’exécution mais inaccessible. Vérifiez les numéros de port de service et le nom du service.