Programação Por Equipe DevBras

Capa do artigo: Acessar MySQL em IP privado com túnel SSH, sem abrir a porta 3306 para a internet

Acessar MySQL em IP privado com túnel SSH, sem abrir a porta 3306 para a internet

Use o servidor que já alcança o banco como ponte: ssh -L no terminal ou a opção TCP/IP over SSH do Workbench, com usuário de banco restrito e porta fechada para fora.

A Loja Trilha migrou o MySQL para uma VM na nuvem sem IP público, endereço interno 10.0.2.15. O aplicativo, na VM vizinha 10.0.1.5, conecta normalmente. O analista Marco, em casa, abre o MySQL Workbench e recebe tempo esgotado. A sugestão que aparece no chat da equipe é a de sempre: "libera a 3306 no firewall para o IP da casa dele". Na semana seguinte o IP da casa muda, alguém troca a regra por "qualquer origem" e o banco fica exposto para a internet inteira.

A resposta curta: entre por SSH na máquina que já alcança o banco e encaminhe uma porta local. O Workbench conecta em 127.0.0.1:3307 no notebook, o SSH carrega a conexão criptografada até a VM 10.0.1.5, e de lá ela segue pela rede privada até 10.0.2.15:3306. A porta do MySQL nunca é publicada.

Por que o túnel funciona e a porta aberta é o erro

Um banco em IP privado só é alcançável de dentro da rede da nuvem. Isso é uma proteção, não um defeito. A VM do aplicativo está dentro dessa rede e tem uma porta SSH aberta para administração. O encaminhamento de porta do SSH (a opção -L) aproveita esse acesso: tudo que entra numa porta do seu notebook é levado, dentro da sessão SSH, até a VM, que abre a conexão real com o banco como se fosse ela a cliente.

Abrir a 3306 para fora troca uma porta protegida por chave SSH por uma protegida só por usuário e senha do banco, e expõe o MySQL a varreduras automáticas que rodam o tempo todo. Mesmo restrita a um IP, a regra tende a ser afrouxada no primeiro problema. Se a ideia é a aplicação acessar o banco em outro servidor, o caminho é rede privada, como em MySQL em outro servidor; o túnel é para acesso humano e pontual.

Como montar o túnel

  1. Garanta acesso SSH por chave à VM ponte (10.0.1.5 por dentro, 203.0.113.10 por fora, no exemplo). O passo a passo está em chave SSH na VM.
  2. Crie um usuário de banco só para você, com o mínimo de permissão e aceitando conexão a partir do IP privado da ponte.
  3. Abra o túnel pelo terminal ou pelo Workbench.
  4. Conecte o cliente em 127.0.0.1 na porta local escolhida.
  5. Feche o túnel ao terminar.
  6. Confirme que a 3306 não responde de fora.

O usuário do banco

Do ponto de vista do MySQL, a conexão vem da VM ponte, não do seu notebook. Por isso o host do usuário é o IP privado dela:

CREATE USER 'marco_leitura'@'10.0.1.5' IDENTIFIED BY 'senha-longa-gerada-pelo-gerenciador';
GRANT SELECT ON loja.* TO 'marco_leitura'@'10.0.1.5';

Somente leitura, só no schema da loja. Para uma correção pontual, conceda a permissão necessária e revogue depois. Não use root: um comando errado digitado no fim do expediente com root afeta o banco inteiro.

Pelo terminal

O cliente OpenSSH já vem no Linux, no macOS e no Windows 10 e 11. O comando:

ssh -N -L 127.0.0.1:3307:10.0.2.15:3306 deploy@203.0.113.10

Lendo da esquerda para a direita: -N não abre um shell, só mantém o túnel; -L 127.0.0.1:3307 escuta na porta 3307 apenas no seu notebook; 10.0.2.15:3306 é o destino visto a partir da ponte. Prefixar com 127.0.0.1 evita que outras máquinas da sua rede de casa usem o túnel. Enquanto o comando roda, em outro terminal:

mysql -h 127.0.0.1 -P 3307 -u marco_leitura -p loja

Use 127.0.0.1, não localhost: no cliente mysql em Linux e macOS, localhost significa conectar pelo socket local, e o túnel não é usado. Escolhi 3307 para não colidir com um MySQL que você talvez tenha instalado no próprio notebook.

Deixando fixo no arquivo de configuração

Em ~/.ssh/config:

Host banco-loja
    HostName 203.0.113.10
    User deploy
    IdentityFile ~/.ssh/id_ed25519
    LocalForward 127.0.0.1:3307 10.0.2.15:3306
    ExitOnForwardFailure yes
    ServerAliveInterval 30

Agora basta ssh -N banco-loja. O ExitOnForwardFailure faz o SSH sair com erro se não conseguir abrir a porta local, em vez de conectar e deixar você achando que o túnel existe. O ServerAliveInterval mantém a sessão viva em redes que derrubam conexões ociosas.

Pelo MySQL Workbench

Na nova conexão, escolha o método "Standard TCP/IP over SSH". Em SSH Hostname, coloque 203.0.113.10:22; em SSH Username, deploy; em SSH Key File, o caminho da sua chave privada. Em MySQL Hostname, coloque 10.0.2.15, porta 3306, e o usuário marco_leitura. O Workbench abre e fecha o túnel sozinho junto com a conexão. Outros clientes gráficos, como DBeaver, têm opção equivalente de túnel SSH nas configurações da conexão.

Restringindo o que a ponte permite

Por padrão, quem tem acesso SSH à ponte pode encaminhar para qualquer destino que ela alcance. No sshd_config da ponte, dá para limitar com PermitOpen, por exemplo num bloco Match User para o usuário de acesso ao banco, permitindo apenas 10.0.2.15:3306. Teste a mudança mantendo uma sessão aberta, para não se trancar fora. E a chave privada fica no seu notebook, não em chat nem em chamado: veja chave SSH não viaja em ticket.

Provedores de nuvem também oferecem serviços gerenciados de acesso, como bastion e gerenciadores de sessão, que fazem o mesmo papel sem você manter a porta 22 aberta para a internet. Vale considerar quando a equipe cresce.

Conferindo que o banco não está exposto

Na VM do banco, veja em que endereço o MySQL escuta:

sudo ss -tlnp | grep 3306

Se aparece 0.0.0.0:3306, ele escuta em todas as interfaces; a proteção depende do firewall e da ausência de IP público. Se a VM tem só IP privado, isso é aceitável; se tem IP público, ajuste o bind-address para o IP privado. De uma máquina fora da nuvem, tente nc -vz IP-PUBLICO 3306: o resultado esperado é falha de conexão ou tempo esgotado.

Erros comuns

  • Abrir a 3306 no firewall "só para um IP". A regra é afrouxada no primeiro imprevisto e o banco fica exposto a varreduras.
  • Conectar em localhost em vez de 127.0.0.1. O cliente usa o socket local e você conecta no banco errado ou em nenhum.
  • Criar o usuário do banco com o IP do notebook. O MySQL vê a conexão vindo da ponte e recusa o acesso.
  • Usar root do banco pelo túnel. Um comando errado tem alcance total.
  • Escutar o túnel em todas as interfaces. Qualquer um na rede do café usa a sua porta 3307.
  • Deixar o túnel aberto em máquina compartilhada. Quem senta depois tem um caminho direto até o banco.

Checklist

  • O acesso SSH à ponte é por chave, sem senha.
  • O usuário de banco tem permissão mínima e host igual ao IP privado da ponte.
  • O túnel escuta só em 127.0.0.1.
  • O cliente conecta em 127.0.0.1 na porta local escolhida.
  • O túnel é fechado ao terminar.
  • A 3306 não responde a partir da internet.
  • A aplicação em produção acessa o banco pela rede privada, sem túnel.

De uma rede fora da sua nuvem, rode um teste de conexão na porta 3306 do IP público do servidor de banco: ela responde? Se responde, feche antes de montar qualquer túnel.

Avalie este artigo

Referência: https://thesubtlepath.com/mysql/mysql-workbench-managing-mysql-behind-a-private-ip/