Compartilhar via


Expor o Apache Superset à Internet

Este artigo descreve como expor o Apache Superset à Internet.

Seleção de nome do host

  1. Decida sobre um nome de host para o Superset.

    A menos que você esteja usando um nome DNS personalizado, esse nome de host deve corresponder ao padrão: <superset-instance-name>.<azure-region>.cloudapp.azure.com. O superset-instance-name deve ser exclusivo na região do Azure.

    Exemplo: myuniquesuperset.westus3.cloudapp.azure.com

  2. Obtenha um certificado TLS para o nome do host, coloque-o dentro do seu Key Vault e o chame de aks-ingress-tls. Saiba como colocar um certificado em um Azure Key Vault.

Entrada da instalação

As instruções a seguir adicionam uma segunda camada de autenticação na forma de um proxy de autorização OAuth usando o Oauth2Proxy. Essa camada significa que nenhum cliente não autorizado alcança o aplicativo Superset.

  1. Adicione os seguintes segredos ao Key Vault.

    Nome do Segredo Descrição
    client-id Sua ID do cliente da entidade de serviço do Azure. O proxy OAuth requer que essa ID seja um segredo.
    oauth2proxy-redis-password Senha de cache do proxy. A senha usada pelo proxy OAuth para acessar a instância de implantação do Redis de back-end no Kubernetes. Gere uma senha forte.
    oauth2proxy-cookie-secret Segredo do cookie de 32 caracteres, usado para criptografar os dados de cookie. Esse segredo deve ter 32 caracteres de comprimento.
  2. Adicione esses retornos de chamada à configuração do seu aplicativo Superset no Azure AD.

    • https://{{superset_hostname}}/oauth2/callback
      • para o Proxy OAuth2
    • https://{{superset_hostname}}/oauth-authorized/azure
      • para Superset
  3. Implante o controlador ngninx de entrada no 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"
    

    Para obter instruções detalhadas, confira as instruções do Azure aqui.

    Observação

    As etapas do controlador nginx de entrada usam o namespace do Kubernetes ingress-basic. Isso precisa ser modificado para usar o namespace default. Por exemplo: NAMESPACE=default

  4. Crie uma Classe de Provedor de Segredos TLS.

    Esta etapa descreve como o certificado TLS é lido do Key Vault e transformado em um segredo do Kubernetes a ser usado pela entrada:

    Atualize no seguinte yaml:

    • {{MSI_CLIENT_ID}} - A ID do cliente da identidade gerenciada atribuída ao cluster Superset ($MANAGED_IDENTITY_RESOURCE).
    • {{KEY_VAULT_NAME}} – O nome do Azure Key Vault que contém os segredos.
    • {{KEY_VAULT_TENANT_ID}} - O guid do identificador do locatário do Azure em que o Key Vault está localizado.

    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. Criar classe de provedor de segredo OauthProxy.

    Atualize no seguinte yaml:

    • {{MSI_CLIENT_ID}} - A ID do cliente da identidade gerenciada atribuída ao cluster Superset ($MANAGED_IDENTITY_RESOURCE).
    • {{KEY_VAULT_NAME}} – O nome do Azure Key Vault que contém os segredos.
    • {{KEY_VAULT_TENANT_ID}} – O GUID do identificador do locatário do Azure em que o cofre de chaves está.

    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. Crie uma configuração para o Proxy OAuth.

    Atualize no seguinte yaml:

    • {{superset_hostname}} — o nome do host voltado para a internet escolhido na seleção de nome do host
    • {{tenant-id}} - O guid do identificador do locatário do Azure em que sua entidade de serviço foi criada.

    Opcional: atualize a lista de email_domains. Exemplo: 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. Implantar recursos do 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. Atualize o rótulo DNS no IP público associado.

    1. Abra seu cluster do Kubernetes do AKS no Superset no portal do Azure.

    2. Selecione "Propriedades" na navegação à esquerda.

    3. Abra o link "Grupo de recursos de infraestrutura".

    4. Localize o endereço IP público com estas marcas:

      {
        "k8s-azure-cluster-name": "kubernetes",
        "k8s-azure-service": "default/ingress-nginx-controller"
      }
      
    5. Selecione "Configuração" na navegação esquerda do IP público.

    6. Insira o rótulo do nome DNS com o <superset-instance-name> definido na seleção de nome do host.

  9. Verifique se sua entrada para o OAuth está configurada.

    Execute kubectl get ingress para ver as duas entradas criadas, azure-trino-superset e oauth2-oauth2-proxy. O endereço IP corresponde ao IP público da etapa anterior.

    Da mesma forma, ao executar kubectl get services você deverá ver que ingress-nginx-controller recebeu um EXTERNAL-IP.

    Dica

    Você pode abrir o http://{{superset_hostname}}/oauth2 para testar se o caminho do OAuth está funcionando.

  10. Defina uma entrada para fornecer acesso ao Superset, mas redirecione todas as chamadas não autorizadas para /oauth.

    Atualize no seguinte yaml:

    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. Implante sua entrada.

          kubectl apply -f ingress.yaml
    
  12. Testar.

    Abra https://{{superset_hostname}}/ no navegador.

Solução de problemas de entrada

Dica

Para redefinir a implantação da entrada, execute esses comandos:

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

Após excluir os recursos, você vai precisar reiniciar essas instruções desde o início.

Certificado de segurança inválido: certificado falso do Controlador de Entrada do Kubernetes

Esse problema causa um erro de verificação de certificado TLS no seu navegador/cliente. Para ver esse erro, inspecione o certificado em um navegador.

A causa usual desse problema é que o certificado está configurado incorretamente:

  • Verifique se você pode ver seu certificado no Kubernetes: kubectl get secret ingress-tls-csi --output yaml

  • Verifique se seu CN corresponde ao CN fornecido no seu certificado.

    • A incompatibilidade de CNs é registrada no pod da entrada. Esses logs podem ser vistos executando kubectl logs <ingress pod>.

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

    O erro de incompatibilidade de CN é descrito com essa linha de log:

    O certificado SSL "default/ingress-tls-csi" não contém um Nome Comum ou Nome Alternativo da Entidade para o servidor "{nome do servidor}": x509: o certificado é válido para um {nome do host inválido}, não o {nome do host real}

Não foi possível resolver o host

Se o nome do host não puder ser resolvido para a instância do Superset, o IP público não terá um nome do host atribuído. Sem essa atribuição, o DNS não pode resolver o nome do host.

Verifique as etapas na seção Atualizar o rótulo DNS no IP público associado.

404 / nginx

O controlador de entrada Nginx não consegue localizar o Superset. Verifique se o Superset está implantado executando kubectl get services e verificando a presença de um serviço superset. Verifique se o serviço de back-end em ingress.yaml corresponde ao nome do serviço usado para o Superset.

503 Serviço temporariamente indisponível/nginx

O serviço está em execução, mas inacessível. Verifique os números da porta de serviço e o nome do serviço.