Expor o Apache Superset à Internet
Este artigo descreve como expor o Apache Superset à Internet.
Seleção de nome do host
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
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.
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. 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
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 namespacedefault
. Por exemplo:NAMESPACE=default
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}}"
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
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
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
Atualize o rótulo DNS no IP público associado.
Abra seu cluster do Kubernetes do AKS no Superset no portal do Azure.
Selecione "Propriedades" na navegação à esquerda.
Abra o link "Grupo de recursos de infraestrutura".
Localize o endereço IP público com estas marcas:
{ "k8s-azure-cluster-name": "kubernetes", "k8s-azure-service": "default/ingress-nginx-controller" }
Selecione "Configuração" na navegação esquerda do IP público.
Insira o rótulo do nome DNS com o
<superset-instance-name>
definido na seleção de nome do host.
Verifique se sua entrada para o OAuth está configurada.
Execute
kubectl get ingress
para ver as duas entradas criadas,azure-trino-superset
eoauth2-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 queingress-nginx-controller
recebeu umEXTERNAL-IP
.Dica
Você pode abrir o
http://{{superset_hostname}}/oauth2
para testar se o caminho do OAuth está funcionando.Defina uma entrada para fornecer acesso ao Superset, mas redirecione todas as chamadas não autorizadas para
/oauth
.Atualize no seguinte yaml:
{{superset_hostname}}
— o nome do host voltado para a internet escolhido na seleção de nome do host
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
Implante sua entrada.
kubectl apply -f ingress.yaml
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.