Bastion: um jump host dentro do cluster Kubernetes
No navegador não existe a sua máquina para abrir um túnel, então o Bastion leva o terminal para dentro do cluster Kubernetes, como um jump host: um pod temporário e sem privilégios no namespace que você escolher, de onde você usa ssh, curl, nc e afins contra VMs, bancos e serviços que o cluster alcança.
O que faz
- Cria um pod temporário no namespace escolhido e abre um terminal nele, no painel inferior.
- A imagem é docker.io/nicolaka/netshoot:v0.16@sha256:b09d9b21381f47a79b3cbcb30da25266dc17186ea00ae65e99fdc51396f48e70 (fixada por digest).
- Ferramentas da imagem: ssh, scp, sftp, curl, dig, nslookup, host, nc, socat, telnet, nmap (-sT), iperf3, openssl, ip, ss, jq, git e vim.
- Opcional: uma chave SSH privada, enviada uma vez ao pod e gravada em memória em ~/.ssh/id_kubepier. Ela nunca é guardada no Kubepier nem em log e some com o pod.
- Na web não há túnel para a sua máquina: para isso existe o Túnel seguro do desktop.
Como o pod do bastion é criado
- Perfil PodSecurity "restricted": usuário 1000 (não root), sem escalada de privilégio, sem capabilities, seccomp RuntimeDefault e sistema de arquivos raiz só leitura.
- HOME (16 Mi) e /tmp (64 Mi) ficam em memória.
- Sem token de ServiceAccount e sem variáveis de Service: o pod não fala com a API do Kubernetes.
- Pede 50m de CPU e 64 Mi de memória, com limite de 500m e 256 Mi.
- Sem privilégio não há socket raw: ping, mtr, traceroute e tcpdump não funcionam. Use nc -vz host porta ou curl.
Qual usar?
| Ferramenta | Onde | De onde a conexão parte | Use quando |
|---|---|---|---|
| Shell no pod | Web e desktop | De dentro de um container da aplicação | Você precisa entrar num container que já roda. |
| Shell no nó | Web (admin) e desktop | De um pod privilegiado no próprio nó | O problema é do nó: kubelet, disco, rede do host. |
| Bastion | Só web | De um pod temporário sem privilégios no namespace | Você quer testar ou acessar, pelo navegador, um host que só o cluster alcança (ssh, curl, nc). |
| Túnel seguro | Só desktop | Da sua máquina, passando pelo cluster | Você quer usar os clientes da sua máquina (psql, DBeaver, navegador, ssh) contra um serviço do cluster ou um host da rede dele. |
Passo a passo: pré-requisitos
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: kubepier-bastion
namespace: <namespace>
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["create", "get", "delete", "list"]
- apiGroups: [""]
resources: ["pods/exec"]
verbs: ["create", "get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: kubepier-bastion
namespace: <namespace>
subjects:
- kind: ServiceAccount
name: kubepier-leitura
namespace: kubepier
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: kubepier-bastion - Organização no Pro ou no Team, e você com papel de admin.
- A credencial do cluster precisa de create, get e delete em pods e create em pods/exec no namespace. list em pods é opcional: serve para apagar bastions seus que sobraram. Aplique o Role abaixo, trocando o sujeito pela identidade da credencial do cluster.
- Rede: o bastion só alcança o que a rede do cluster alcança. NetworkPolicies do namespace valem para ele, e NSGs ou security groups da sub-rede dos nós podem bloquear o destino.
Passo a passo: abrir
- Abra o cluster e clique em Bastion, no menu lateral.
- Em Namespace, informe onde o pod vai rodar (letras minúsculas, números e hífen; o padrão é default).
- Se for usar ssh com chave, cole a chave em Chave SSH privada (opcional), ou use Carregar arquivo. Mostrar e Ocultar alternam a visualização.
- Clique em Abrir bastion. A tela mostra cada etapa: criando o pod, esperando um node, baixando a imagem, rodando e, se houver, chave gravada em ~/.ssh/id_kubepier.
- O terminal abre quando o pod fica Running (até 120 segundos).
Passo a passo: usar
Exemplos para copiar no terminal do bastion:
# SSH até uma VM interna (com a chave colada ao abrir)
ssh -i ~/.ssh/id_kubepier ubuntu@10.0.1.20
# A porta do banco responde?
nc -vz db.interno 5432
# Health check de um serviço interno
curl -v http://servico.interno:8080/health
# Resolução de nome dentro do cluster
dig api.interno
# Copiar um arquivo de um host interno para outro, passando pelo bastion
scp -i ~/.ssh/id_kubepier ubuntu@10.0.1.20:/var/log/app.log /tmp/
scp -i ~/.ssh/id_kubepier /tmp/app.log ubuntu@10.0.1.21:/tmp/ HOME e /tmp ficam em memória e somem quando o bastion fecha. Para trazer arquivos para a sua máquina, use o Túnel seguro do desktop.
Passo a passo: fechar
- Feche o terminal: o pod é apagado na hora.
- O pod também acaba sozinho em 2 horas, num erro, ou se não ficar Running em 120 segundos.
- Depois que a sessão termina, Novo bastion abre outro.
O que é aceito
- Um namespace existente em que a credencial possa criar pods.
- Uma chave privada no formato BEGIN ... PRIVATE KEY, de até 16 KB.
O que não é aceito
- Plano Free; membro.
- Mais de um bastion seu no mesmo cluster.
- Abrir com 3 terminais já abertos (o bastion conta no limite de shells).
- Uma chave que não parece chave privada: o terminal abre sem ela.
- Túnel para a sua máquina (só no desktop).
Limites e tempos
| Limite | Valor |
|---|---|
| Espera o pod ficar Running | 120 segundos |
| Duração máxima | 2 horas |
| Bastions por cluster | 1 por pessoa |
| Terminais abertos (shell e bastion) | 3 por pessoa |
| Chave SSH | até 16 KB |
| Recursos do pod | 50m/64 Mi pedidos, 500m/256 Mi de limite |
Auditoria
- Abertura e fechamento vão para a auditoria da organização (bastion_abrir e bastion_fechar), com quem, quando, cluster, namespace, pod e a duração.
- Nunca o que é digitado, a saída do terminal nem a chave.
Erros comuns
- Sem permissão: a credencial precisa de create, get e delete em pods e create em pods/exec no namespace.
- PodSecurity recusou: o bastion já segue o perfil restricted; confira o rótulo de PodSecurity do namespace.
- Política de admissão recusou: Kyverno, Gatekeeper ou um webhook exige outra coisa, como imagens do registry interno.
- Imagem não baixou: os nodes não saem para o Docker Hub: espelhe docker.io/nicolaka/netshoot:v0.16@sha256:b09d9b21381f47a79b3cbcb30da25266dc17186ea00ae65e99fdc51396f48e70 no seu registry.
- ResourceQuota: o namespace não comporta 50m/64 Mi pedidos e 500m/256 Mi de limite.
- Não ficou Running em 120 s: o pod foi apagado; confira os eventos do namespace.
- Namespace não existe: confira o nome.
- "Too Many Requests": você já tem um bastion neste cluster ou 3 terminais abertos.