Pular para o conteúdo

Checklist: Kubernetes Dashboard com proxy reverso e SSL

Por Equipe Técnica AviraHost · 22 min de leitura · Atualizado em · Kubernetes, Dashboard, proxy-reverso, SSL, Nginx, Let's Encrypt, VPS-Linux, AviraHost · 0

Kubernetes Dashboard com proxy reverso e SSL é a publicação da interface web do cluster por trás de um proxy (como o Nginx) que termina o HTTPS, enquanto o serviço do Dashboard continua acessível só localmente. Isso não dispensa um ServiceAccount com poucas permissões nem restrição de acesso por IP ou VPN. Para instalar e proteger o Dashboard em um VPS Linux, siga estes passos:

  1. Confirme que o cluster (por exemplo K3s) responde com kubectl get nodes e que o Helm está instalado.
  2. Instale o chart oficial do kubernetes-dashboard em um namespace próprio.
  3. Crie um ServiceAccount com a role view e gere um token temporário.
  4. Exponha o Dashboard apenas em 127.0.0.1 com kubectl port-forward gerenciado pelo systemd.
  5. Configure o Nginx como proxy reverso HTTPS para essa porta local e emita o certificado com o Certbot.
  6. Restrinja o acesso por IP, ative o firewall e teste o login e a renovação do certificado.

Pré-requisitos

  • VPS Linux com Ubuntu 24.04 LTS (os comandos de pacote abaixo usam apt), acesso root ou sudo e pelo menos 2 GB de RAM livres para o cluster e o Dashboard.
  • Cluster Kubernetes funcionando. Em um VPS único, o K3s é uma opção leve; veja Otimizar Kubernetes em VPS Linux: recursos e custos eficientes.
  • kubectl configurado para o cluster e Helm 3 instalado.
  • Um subdomínio (neste artigo, dashboard.seudominio.com.br) com registro A apontando para o IP do VPS (exemplo: 203.0.113.10).
  • Portas 80 e 443 liberadas no firewall do VPS.
  • Nginx e Certbot disponíveis no repositório padrão do Ubuntu 24.04 ou via snap.

Checklist de instalação do Dashboard com Helm

Atenção: o repositório do Kubernetes Dashboard foi arquivado e o projeto não recebe manutenção ativa. Antes de expor um painel administrativo do cluster, avalie alternativas mantidas, como o Headlamp, preferencialmente acessível apenas por VPN. Se precisar usar o Dashboard legado, fixe a versão no Helm, verifique a compatibilidade com a versão exata do Kubernetes em uso e nunca o exponha em rede pública sem VPN ou restrição de IP estrita.

A instalação por Helm é o método documentado pelo projeto, pois o chart já traz os componentes de autenticação, API e interface web. Nas versões recentes do chart (7.x), o Dashboard é composto por vários pods e o acesso é feito por um serviço chamado kubernetes-dashboard-kong-proxy, que usa HTTPS interno com certificado autoassinado.

Se você usa K3s, o kubectl já vem junto, mas o arquivo de configuração fica em /etc/rancher/k3s/k3s.yaml. Exporte a variável antes de continuar:

export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
kubectl get nodes

A saída deve mostrar o nó com status Ready. Se o Helm ainda não estiver instalado, use o método oficial do projeto Helm e confirme com helm version.

Adicione o repositório e instale o chart:

helm repo add kubernetes-dashboard https://kubernetes.github.io/dashboard/
helm repo update
helm upgrade --install kubernetes-dashboard kubernetes-dashboard/kubernetes-dashboard \
  --create-namespace --namespace kubernetes-dashboard

Aguarde os pods e confirme o estado:

kubectl -n kubernetes-dashboard get pods
kubectl -n kubernetes-dashboard get svc

Todos os pods devem estar em Running. Na lista de serviços, localize kubernetes-dashboard-kong-proxy, do tipo ClusterIP, na porta 443. Esse tipo de serviço não é acessível de fora do cluster, o que é exatamente o desejado: nenhuma porta do Dashboard fica aberta na internet.

Os nomes dos serviços podem variar conforme a versão do chart. Sempre confira a saída de kubectl get svc antes de apontar qualquer coisa para ele.

Criar ServiceAccount e token de acesso com menor privilégio

O login do Dashboard por token depende de um ServiceAccount, e as permissões dele definem o que quem entra pode fazer no cluster. Comece com a role view, que dá apenas leitura e já vem pronta no Kubernetes.

kubectl -n kubernetes-dashboard create serviceaccount leitor-dashboard

kubectl -n meu-namespace create rolebinding leitor-dashboard-view \
  --clusterrole=view \
  --serviceaccount=kubernetes-dashboard:leitor-dashboard

O comando acima concede a role view apenas no namespace meu-namespace. Se precisar de visibilidade em múltiplos namespaces, crie um RoleBinding separado em cada um deles com o mesmo comando, trocando o namespace. Usar um ClusterRoleBinding daria leitura em todos os namespaces do cluster de uma vez, o que costuma ser mais do que o necessário para um operador com escopo limitado.

Gere o token temporário:

kubectl -n kubernetes-dashboard create token leitor-dashboard

O comando imprime uma string longa (JWT). Ela expira; por padrão, a validade é curta e você pode ajustar com --duration, por exemplo --duration=2h. Prefira tokens de vida curta a tokens permanentes.

Atenção: evite associar o ServiceAccount à role cluster-admin, comum em tutoriais antigos. Com ela, qualquer pessoa com o token administra todo o cluster. A role view não permite ler Secrets, o que reduz o impacto de um vazamento. Se precisar de escrita, crie uma role específica por namespace em vez de liberar tudo.

Guarde o token apenas em um gerenciador de senhas e não o cole em chats ou tickets.

Expor o serviço apenas em localhost

Para o proxy reverso alcançar o Dashboard sem abrir uma porta pública, uma opção simples em VPS único é o kubectl port-forward ligado em 127.0.0.1. O Nginx, rodando no mesmo servidor, encaminha para essa porta local. O Dashboard continua sem exposição direta na internet.

Teste primeiro manualmente:

kubectl -n kubernetes-dashboard port-forward \
  --address 127.0.0.1 svc/kubernetes-dashboard-kong-proxy 8443:443

Em outro terminal, valide com curl. O -k é necessário porque o certificado interno é autoassinado:

curl -k -I https://127.0.0.1:8443/

Você deve ver uma resposta HTTP com código 200, ou um redirecionamento, vinda do Dashboard. Interrompa o teste com Ctrl+C e torne o encaminhamento permanente com uma unidade do systemd:

sudo nano /etc/systemd/system/k8s-dashboard-forward.service
[Unit]
Description=Port-forward do Kubernetes Dashboard para localhost
After=network-online.target k3s.service
Wants=network-online.target

[Service]
Environment=KUBECONFIG=/etc/rancher/k3s/k3s.yaml
ExecStart=/usr/local/bin/kubectl -n kubernetes-dashboard port-forward --address 127.0.0.1 svc/kubernetes-dashboard-kong-proxy 8443:443
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now k8s-dashboard-forward.service
ss -tlnp | grep 8443

O ss deve mostrar a porta 8443 escutando em 127.0.0.1, e nunca em 0.0.0.0. Se o kubectl estiver em outro caminho no seu servidor (confira com which kubectl), ajuste o ExecStart. Se você não usa K3s, remova a referência ao k3s.service e aponte o KUBECONFIG para o seu arquivo.

Como alternativa mais robusta, é possível usar um Ingress Controller dentro do cluster. Aqui seguimos com o Nginx no host porque é o caso mais comum em VPS único e o que já aparece em Como Configurar um Servidor Proxy Reverso com Nginx no VPS Linux.

Configurar o Nginx como proxy reverso

O Nginx recebe as conexões na porta 443 e repassa o tráfego para o Dashboard em 127.0.0.1:8443. Como o backend usa HTTPS com certificado autoassinado, o proxy deve falar HTTPS com ele. Nesta etapa, crie apenas a configuração necessária para validar o domínio com o Certbot; o bloco de proxy será adicionado depois, somente no servidor HTTPS, após o certificado estar emitido.

sudo apt update
sudo apt install -y nginx
sudo mkdir -p /var/www/certbot

Para recursos que usam WebSocket (como logs e terminal de pods), o Nginx precisa de um bloco map no contexto http. Crie um arquivo de configuração separado que o Nginx inclui automaticamente:

sudo nano /etc/nginx/conf.d/connection-upgrade.conf
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

Agora crie o virtual host inicial. Nesta primeira versão, a porta 80 serve apenas o desafio ACME e retorna 404 para todo o restante — o Dashboard não fica exposto em HTTP em nenhum momento:

sudo nano /etc/nginx/sites-available/dashboard.conf
server {
    listen 80;
    server_name dashboard.seudominio.com.br;

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    location / {
        return 404;
    }
}

Ative o site e valide a sintaxe antes de recarregar:

sudo ln -s /etc/nginx/sites-available/dashboard.conf /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Emitir o certificado SSL com Certbot

O certificado SSL Let's Encrypt criptografa o login e o token entre o navegador e o servidor. Antes, confirme que o DNS já aponta para o VPS. O utilitário dig requer o pacote dnsutils:

sudo apt install -y dnsutils
dig +short dashboard.seudominio.com.br

O resultado deve ser o IP do seu VPS (por exemplo, 203.0.113.10). Instale o Certbot e emita o certificado com validação webroot — esse método usa o diretório criado na etapa anterior e não expõe o Dashboard:

sudo apt install -y certbot
sudo certbot certonly --webroot -w /var/www/certbot -d dashboard.seudominio.com.br

O Certbot pede um e-mail e solicita aceite dos termos. Ao final, os arquivos do certificado ficam em /etc/letsencrypt/live/dashboard.seudominio.com.br/.

Com o certificado emitido, substitua o conteúdo de /etc/nginx/sites-available/dashboard.conf pela configuração completa, que inclui o redirecionamento HTTP e o proxy HTTPS:

server {
    listen 80;
    server_name dashboard.seudominio.com.br;

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl;
    server_name dashboard.seudominio.com.br;

    ssl_certificate /etc/letsencrypt/live/dashboard.seudominio.com.br/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/dashboard.seudominio.com.br/privkey.pem;

    location / {
        proxy_pass https://127.0.0.1:8443;
        proxy_ssl_verify off;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_read_timeout 300s;
    }
}

O proxy_ssl_verify off está explícito porque o certificado interno é autoassinado; como a conexão ocorre dentro do próprio servidor, em 127.0.0.1, o risco é baixo. A variável $connection_upgrade é definida pelo bloco map criado na etapa anterior e garante que Connection: upgrade seja enviado apenas em requisições WebSocket, e close nas demais. Aplique e recarregue:

sudo nginx -t
sudo systemctl reload nginx

Teste a renovação automática:

sudo certbot renew --dry-run

A mensagem final deve indicar que a simulação de renovação foi bem-sucedida. Para entender certificados para vários subdomínios, consulte Como Instalar e Configurar o Let's Encrypt Wildcard SSL no VPS Linux.

Após confirmar que o HTTPS funciona (veja a seção de testes a seguir), acrescente cabeçalhos de segurança no bloco server da porta 443 e recarregue:

add_header Strict-Transport-Security "max-age=300" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;

Recarregue com sudo nginx -t && sudo systemctl reload nginx. O valor inicial max-age=300 (5 minutos) permite reverter rapidamente caso algo esteja errado. Depois de validar que o HTTPS funciona de forma estável por alguns dias, aumente para max-age=31536000 (um ano). O HSTS instrui o navegador a converter automaticamente qualquer requisição HTTP para HTTPS nesse host; se o endpoint HTTPS deixar de funcionar ou apresentar certificado inválido, o acesso falhará até o max-age expirar.

Restringir acesso por IP e autenticação extra

Mesmo com HTTPS, o painel de administração não deve ficar aberto a qualquer visitante. Uma camada extra no proxy reduz o risco de exploração de falhas e de força bruta no token. A forma mais direta é limitar por IP dentro do bloco location / do servidor HTTPS:

location / {
    allow 198.51.100.25;
    deny all;

    proxy_pass https://127.0.0.1:8443;
    proxy_ssl_verify off;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
}

Substitua 198.51.100.25 pelo seu IP fixo. Quem tentar acessar de outro endereço recebe 403. Se o seu IP muda, a opção mais segura é acessar por VPN e liberar só o IP da VPN; veja Como Instalar e Configurar o OpenVPN no VPS Linux para Acesso Seguro Remoto.

Não use autenticação básica do Nginx (auth_basic) na frente do Dashboard. O frontend do Dashboard envia o token de acesso no cabeçalho Authorization: Bearer em todas as chamadas à API. O auth_basic usa o mesmo cabeçalho Authorization, e os dois entram em conflito: o login por token deixa de funcionar de forma consistente. Se precisar de uma barreira adicional além da restrição por IP, use VPN ou soluções que não disputem o cabeçalho Authorization, como oauth2-proxy ou autenticação por certificado de cliente no Nginx.

Por fim, configure o firewall com UFW. Em um nó K3s, as faixas de pods e de serviços precisam ser liberadas explicitamente para que a comunicação interna do cluster (CoreDNS, pods, serviços) continue funcionando. Configure a política padrão e adicione as regras antes de ativar:

sudo ufw default deny incoming
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow from 10.42.0.0/16 to any
sudo ufw allow from 10.43.0.0/16 to any
sudo ufw enable
sudo ufw status numbered

Os CIDRs 10.42.0.0/16 (pods) e 10.43.0.0/16 (serviços) são os padrões do K3s; ajuste se o seu cluster usar faixas diferentes. Em cluster multi-nó, libere também 6443/tcp, 8472/udp e 10250/tcp entre os nós. A porta 8443 não precisa de regra: ela escuta só em localhost e não é acessível de fora. Após ativar, audite as regras com sudo ufw status numbered e remova as que não forem necessárias; regras criadas pelo runtime do Kubernetes para NodePort ou LoadBalancer podem não estar representadas pelo UFW e precisam ser verificadas separadamente com sudo nft list ruleset ou sudo iptables -L -n.

Testar o acesso e validar a segurança

Com tudo configurado, o teste final confirma que o HTTPS funciona, que o backend não vaza e que o login por token entra. Do seu computador:

curl -I https://dashboard.seudominio.com.br

Você deve receber uma resposta HTTP/2 ou HTTP/1.1 com status 200. Verifique também o redirecionamento do HTTP:

curl -I http://dashboard.seudominio.com.br

Deve voltar um status 301 com o cabeçalho Location apontando para a versão HTTPS. Em seguida, acesse a URL no navegador, escolha a opção de login por Token e cole o token gerado.

Checklist final de validação:

  • Pods do namespace kubernetes-dashboard em Running.
  • Porta 8443 escutando apenas em 127.0.0.1 (ss -tlnp).
  • Certificado válido e renovação testada com certbot renew --dry-run.
  • Acesso restrito por IP ou VPN.
  • ServiceAccount com role view por namespace, sem cluster-admin.
  • Firewall ativo: política padrão deny incoming, CIDRs do K3s liberados, regras auditadas com sudo ufw status numbered.

Para acompanhar consumo de CPU e memória do servidor depois da instalação, o monitoramento de recursos com Netdata no VPS Linux ajuda a perceber excesso de uso cedo.

Problemas comuns e como resolver

Sintoma: erro 502 Bad Gateway ao abrir o subdomínio

Causa: o Nginx não consegue falar com 127.0.0.1:8443, normalmente porque o port-forward caiu ou o serviço tem outro nome.
Solução: verifique sudo systemctl status k8s-dashboard-forward.service e ss -tlnp | grep 8443. Confirme o nome do serviço com kubectl -n kubernetes-dashboard get svc. Veja também /var/log/nginx/error.log. Se o proxy_pass usa http:// em vez de https://, corrija: o backend só responde em HTTPS.

Sintoma: o Certbot falha na validação do domínio

Causa: o DNS ainda não aponta para o VPS, a porta 80 está bloqueada no firewall ou outro serviço ocupa a porta 80.
Solução: confira com dig +short dashboard.seudominio.com.br, libere a porta 80 no UFW e no firewall do provedor, e verifique se há um único Nginx escutando com ss -tlnp | grep ':80'. Se o DNS passa por um proxy como a Cloudflare, o ideal é desativar o proxy durante a emissão ou usar validação por DNS.

Sintoma: o login com token é rejeitado ou volta à tela inicial

Causa: o token expirou, foi copiado com quebra de linha, o ServiceAccount não tem as permissões esperadas ou há conflito com autenticação adicional na camada do proxy.
Solução: gere um novo token com kubectl -n kubernetes-dashboard create token leitor-dashboard, copie-o em uma única linha e verifique os logs dos componentes de autenticação do Dashboard. Para diagnosticar loops de redirecionamento ou URLs geradas com esquema incorreto, investigue se os cabeçalhos proxy_set_header X-Forwarded-Proto estão presentes no bloco HTTPS. Se alguma camada de autenticação adicional estiver ativa na frente do Dashboard, remova-a para isolar a causa.

Sintoma: o Dashboard abre, mas mostra "forbidden" nas listas

Causa: o ServiceAccount não tem permissão para o recurso, o que é esperado com a role view em itens como Secrets.
Solução: confirme com kubectl auth can-i list pods --as=system:serviceaccount:kubernetes-dashboard:leitor-dashboard -n meu-namespace. Se precisar de mais acesso, crie uma role específica para o namespace necessário em vez de usar cluster-admin.

Sintoma: erro 403 ao acessar de casa ou do celular

Causa: seu IP mudou e não está mais na diretiva allow.
Solução: atualize o IP no virtual host, rode sudo nginx -t e recarregue. Para evitar manutenção constante, acesse por VPN com IP fixo.

Perguntas frequentes

Como instalar o Kubernetes Dashboard em um VPS Linux?

Com um cluster funcionando (por exemplo K3s) e o Helm instalado, adicione o repositório oficial do kubernetes-dashboard e execute helm upgrade --install em um namespace próprio. Depois crie um ServiceAccount com a permissão desejada, gere um token e valide que os pods estão em Running. O acesso externo deve ser feito por proxy reverso com HTTPS, nunca expondo o serviço diretamente.

Por que usar proxy reverso com SSL no Kubernetes Dashboard?

O Dashboard permite administrar o cluster, então o tráfego e o token de login precisam ser criptografados. O proxy reverso, como o Nginx, centraliza o certificado SSL, permite restringir IPs, adicionar autenticação extra e esconder o serviço interno. Assim a porta do Dashboard fica acessível apenas localmente.

Posso expor o Kubernetes Dashboard diretamente na internet?

Não é recomendado. Um Dashboard exposto com permissões amplas dá controle sobre o cluster a quem obtiver o token ou explorar uma falha. Prefira publicá-lo atrás de proxy reverso com HTTPS, restrição por IP ou VPN e um ServiceAccount com o mínimo de permissões necessárias.

Como gerar o token de acesso do Kubernetes Dashboard?

Crie um ServiceAccount e um RoleBinding adequado no namespace que deseja visualizar, depois execute kubectl -n kubernetes-dashboard create token nome-do-serviceaccount. O token é temporário e deve ser colado na tela de login. Use permissões somente leitura sempre que possível, como a role view.

Como emitir o certificado SSL para o Dashboard com Nginx?

Aponte o DNS do subdomínio para o IP do VPS, configure um virtual host Nginx que sirva apenas o desafio ACME na porta 80 e execute certbot certonly --webroot -w /var/www/certbot -d dashboard.seudominio.com.br. Após a emissão, atualize o virtual host com o bloco HTTPS completo incluindo proxy_pass. Confirme a renovação automática com certbot renew --dry-run.

Conclusão

Publicar o Dashboard com segurança depende de camadas: serviço só em localhost, HTTPS no proxy, acesso restrito e token com poucas permissões. Cada camada reduz o risco de alguém assumir o controle do cluster.

  • Revise o ServiceAccount: mantenha a role view por namespace com RoleBinding e gere tokens de curta duração com --duration.
  • Restrinja o subdomínio por IP ou VPN e confirme que a porta 8443 escuta apenas em 127.0.0.1.
  • Teste a renovação com certbot renew --dry-run e acompanhe o servidor com monitoramento de recursos.

Leia também

Precisa de ajuda com Kubernetes em VPS?

Um VPS com recursos dedicados facilita rodar K3s, Nginx e o Dashboard com HTTPS e firewall sob seu controle. Se precisar de apoio para dimensionar o servidor, nossa equipe pode orientar.

Conheça os planos de VPS


Esta resposta foi útil?