Faça o Hardening de um Servidor Linux
Suba sua própria máquina Linux descartável (Docker ou Vagrant) e leve-a de uma instalação padrão a uma base "hardened": usuário não-root com sudo, SSH só por chave, firewall travado, superfície de serviços enxuta e fail2ban vigiando a porta.
Problema
Um servidor Linux recém-provisionado não é seguro para expor à internet. De fábrica ele normalmente vem com: uma conta `root` acessível via SSH, autenticação por senha habilitada, todos os serviços padrão rodando e escutando em todas as interfaces, nenhuma regra de firewall e nenhuma proteção contra tentativas de login por força bruta. Scanners automatizados encontram hosts novos minutos depois de ficarem públicos — você não tem a opção de "endurecer depois". Neste lab você vai provisionar uma VM ou container Linux descartável que você controla totalmente, e então percorrer um checklist real de hardening contra ela: criar um usuário administrativo não-root, desabilitar o login root via SSH, trocar para autenticação só por chave, configurar um firewall que nega por padrão, desabilitar ou remover serviços que você não usa, e instalar o fail2ban para bloquear automaticamente hosts que martelam sua porta SSH. Cada passo termina com um comando que você roda para **provar** que o controle está no lugar — hardening que você não consegue verificar é hardening no qual você não pode confiar. > Pratique só contra uma VM/container descartável que você controla (Docker, > Vagrant, ou uma instância de cloud descartável sua). Nunca rode estes passos > exploratórios — especialmente as checagens de "antes" — contra um servidor que > você não é dono ou administrador.
Objetivos
Ao final deste lab você será capaz de:
- Provisionar um host Linux descartável para prática de segurança (container
Docker com SSH, ou uma VM Vagrant). - Criar um usuário não-root com privilégios sudo e confirmar que ele consegue
administrar a máquina. - Desabilitar o login root e a autenticação por senha via SSH, trocando para
autenticação por chave. - Configurar o
ufw(ou firewall equivalente) para negar todo tráfego de entrada
por padrão e permitir só as portas que você realmente precisa. - Auditar e desabilitar serviços desnecessários em execução para reduzir a
superfície de ataque. - Instalar e configurar o
fail2banpara banir automaticamente hosts que falham
repetidamente o login SSH. - Verificar cada controle com um comando concreto, não só "deveria estar funcionando".
Pré-requisitos
Para completar este lab você vai precisar de:
- Docker instalado (caminho recomendado: um container Linux com
sshd, ex. uma
imagem Ubuntu), ou Vagrant + VirtualBox/libvirt se preferir uma VM completa. - Um terminal e um cliente SSH (
ssh,ssh-keygen) na sua máquina host. - Acesso root ou sudo dentro da própria VM/container descartável (você está
endurecendo uma máquina que você provisionou, não uma compartilhada). - Não é exigida experiência prévia com administração Linux, mas familiaridade
com um shell ajuda.
O modelo mental: negar por padrão, superfície mínima
Hardening não é um único interruptor — é uma pilha de controles independentes,
cada um fechando uma porta diferente. A filosofia que amarra tudo isso é
negar por padrão, superfície mínima: nada é permitido a menos que você
permita explicitamente, e nada roda a menos que você realmente precise que rode.
Visão do atacante sobre uma máquina "hardened"
│
▼ sem login root via SSH (Passo 2)
▼ sem autenticação por senha, só chave (Passo 3)
▼ firewall nega tudo o mais (Passo 4)
▼ menos serviços escutando (Passo 5)
▼ fail2ban bane IPs de força bruta (Passo 6)
▼
um alvo bem menor e bem mais lento
Nenhum desses controles sozinho torna um servidor "seguro" — segurança é em
camadas (defense in depth). Uma chave SSH vazada ainda entra se você não tiver
firewall; uma porta de firewall aberta para um serviço vulnerável ainda é
explorada se o login root estiver desabilitado. Você endurece cada camada porque
não sabe qual delas o atacante vai atingir primeiro.
Por que praticar numa máquina descartável
Errar um passo durante o hardening (ex.: desabilitar autenticação por senha
antes da sua chave funcionar) pode te trancar para fora de um servidor real. Um
container ou VM descartável que você pode destruir e recriar em segundos remove
esse medo — quebre, aprenda, derrube, comece de novo. É exatamente para isso que
este lab serve.
Como trabalhar neste lab
Faça os passos em ordem — passos posteriores assumem que os anteriores estão
feitos (ex.: você precisa do seu usuário não-root e das chaves SSH funcionando
antes de desabilitar o login root/senha, ou você vai se trancar para fora).
Cada passo termina com um comando de verificação; não avance até ele passar.
Passos
-
Provisione um host Linux descartável
Você precisa de uma máquina Linux real e descartável com acesso SSH. O
caminho mais rápido é um container Docker rodandosshd; o caminho mais
realista é uma VM completa via Vagrant. Escolha um.Opção A — Docker (mais rápido)
# Constrói uma imagem Ubuntu mínima com servidor SSH e uma senha root inicial cat > Dockerfile <<'EOF' FROM ubuntu:22.04 RUN apt-get update && apt-get install -y openssh-server sudo && \ mkdir /var/run/sshd && \ echo 'root:changeme123' | chpasswd && \ sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config && \ sed -i 's/#PasswordAuthentication yes/PasswordAuthentication yes/' /etc/ssh/sshd_config EXPOSE 22 CMD ["/usr/sbin/sshd", "-D"] EOF docker build -t hardening-lab . docker run -d --name hardening-lab -p 2222:22 hardening-lab # Confirme que consegue acessar (senha: changeme123) ssh -p 2222 root@localhostOpção B — Vagrant (mais perto de uma VM real)
vagrant init ubuntu/jammy64 vagrant up vagrant ssh # confirme que você entra na máquinaQualquer que seja sua escolha, ao final deste passo você deve estar
logado como root (ou viavagrant sshcom sudo sem senha), com uma
forma conhecida de voltar a entrar caso algo dê errado: no Docker,
docker exec -it hardening-lab bashsempre te dá um shell root mesmo que o
SSH quebre; no Vagrant,vagrant sshda mesma forma contorna suas
mudanças de hardening.Checkpoint
Rode
whoamiecat /etc/os-releasedentro da máquina e confirme que você
é root numa máquina Ubuntu/Debian nova. Anote em algum lugar o comando de
"saída de emergência" (docker execouvagrant ssh) — você vai querer se
um passo posterior der errado.Entregável deste passo: um host Linux descartável rodando, no qual você
consegue entrar via SSH, mais uma saída de emergência documentada que não
depende do SSH. -
Crie um usuário não-root com sudo
Rodar tudo como
rootsignifica que qualquer processo comprometido — um bug
na sua aplicação, uma dependência maliciosa, um script sequestrado — tem
controle total da máquina instantaneamente. Um usuário não-root comsudo
te dá o mesmo poder administrativo sob demanda, com uma trilha de
auditoria e um raio de impacto menor para qualquer coisa que rode semsudo.# Como root: adduser --disabled-password --gecos "" opslab usermod -aG sudo opslab # Debian/Ubuntu; use o grupo 'wheel' no RHEL/Fedora # Dê uma senha ao novo usuário por enquanto (você vai desabilitar senha via SSH depois) passwd opslab # Confirme que o grupo sudo concede o que você espera cat /etc/sudoers.d/* /etc/sudoers 2>/dev/null | grep -i sudoTroque para ele e confirme que o sudo funciona antes de mexer na
configuração do SSH:su - opslab sudo whoami # deve imprimir: rootPor que essa ordem importa
Você cria e verifica o usuário não-root antes de travar o acesso root
via SSH no Passo 3. Se você desabilitar o login root primeiro e o novo
usuário ainda não estiver funcionando, você pode se trancar completamente
para fora (num servidor real — nesta máquina descartável você só usaria a
saída de emergência e começaria de novo, mas construa o hábito agora).Checkpoint
De um terminal novo (não a sessão root), rode:
ssh -p 2222 opslab@localhost # ou o equivalente `vagrant ssh` sudo whoami # deve imprimir "root" sem erroEntregável deste passo: um usuário não-root que consegue autenticar e
rodarsudo whoamicom sucesso, confirmado a partir de um login separado,
não só na sessão em que você o criou. -
SSH só por chave, sem login root
Senhas são adivinháveis e phishable; pares de chave SSH não são. E mesmo uma
senha forte norootestá a uma credencial de distância do comprometimento
total — remover a capacidade do root de logar via SSH inteiramente significa
que um atacante precisa primeiro comprometer um usuário nomeado e auditável
e escalar via sudo.Gere e instale uma chave
Na sua máquina host (não dentro da máquina):
ssh-keygen -t ed25519 -f ~/.ssh/hardening_lab -C "hardening-lab" ssh-copy-id -p 2222 -i ~/.ssh/hardening_lab.pub opslab@localhost # ou manualmente: acrescente o conteúdo do .pub em # /home/opslab/.ssh/authorized_keys dentro da máquina (modo 600, dono opslab)Confirme que o login por chave funciona antes de desabilitar senhas:
ssh -p 2222 -i ~/.ssh/hardening_lab opslab@localhost 'whoami'Trave o sshd_config
Dentro da máquina, edite
/etc/ssh/sshd_config:PermitRootLogin no PasswordAuthentication no ChallengeResponseAuthentication no PubkeyAuthentication yes AllowUsers opslabAplique e reinicie:
sudo sshd -t # valide a sintaxe antes de reiniciar sudo systemctl restart sshdCheckpoint — prove as duas metades
# 1) Login por chave do opslab ainda funciona ssh -p 2222 -i ~/.ssh/hardening_lab opslab@localhost 'whoami' # 2) Login por senha é recusado (deve falhar / ser rejeitado, não pedir com sucesso) ssh -p 2222 -o PubkeyAuthentication=no opslab@localhost # 3) Login root é recusado por completo, mesmo com a senha certa ssh -p 2222 root@localhostSe os passos 2 ou 3 acima ainda deixarem você entrar, o
sshd_confignão
recarregou — reveja a saída dosudo sshd -te osystemctl status sshd.Entregável deste passo: o
opslabsó loga com a chave,
PasswordAuthenticationePermitRootLoginestão confirmados desligados
por uma tentativa de login real que falhou, não só lendo o arquivo de config. -
Trave o firewall com ufw
Mesmo com o SSH endurecido, todo outro serviço na máquina ainda é alcançável
de qualquer lugar a menos que um firewall diga o contrário. Oufw
(Uncomplicated Firewall) te dá uma política de negar-por-padrão em poucos
comandos.sudo apt-get update && sudo apt-get install -y ufw # Nega tudo de entrada por padrão, permite toda saída sudo ufw default deny incoming sudo ufw default allow outgoing # Permita só o que você realmente precisa. Limite a taxa do SSH contra força bruta. sudo ufw limit 22/tcp comment 'SSH, com rate-limit' # Adicione mais só quando precisar, ex.: # sudo ufw allow 80/tcp comment 'HTTP' # sudo ufw allow 443/tcp comment 'HTTPS' sudo ufw enableA ordem importa dentro de um container. Rodar
sudo ufw enableantes
de confirmar que sua regra de SSH está exatamente certa pode derrubar sua
própria conexão. No Docker especificamente, oufwinterage de forma
estranha com o mapeamento de portas baseado emiptables— se você estiver
no Docker, trate este passo como aprender o fluxo de trabalho do ufw e
verifique comufw status; para um firewall totalmente imposto na frente
de mapeamentos de porta do Docker, um alvo Vagrant/VM é mais realista.Por que
limitem vez deallowpara o SSHufw limit 22/tcpnega um IP que faz mais de 6 tentativas de conexão em 30
segundos — uma primeira linha de defesa barata contra força bruta,
complementar ao (não substituta do) fail2ban no Passo 6.Checkpoint
sudo ufw status verboseConfirme que a saída mostra:
- Padrão:
deny (incoming),allow (outgoing) - Só as portas que você permitiu explicitamente aparecem como
ALLOW/LIMIT - Nada mais está aberto
Depois, da sua máquina host, tente alcançar uma porta que você não
abriu (ex.:nc -zv localhost 2222deve funcionar, mas uma porta que você
nunca permitiu, como 9999, deve dar timeout ou ser recusada).Entregável deste passo: a saída de
ufw status verbosemostrando uma
política de entrada negar-por-padrão com uma allowlist explícita e mínima —
e uma tentativa de conexão falha a uma porta que você não abriu, provando
que a negação realmente vale. - Padrão:
-
Audite e desabilite serviços desnecessários
Todo serviço em execução é uma vulnerabilidade em potencial, mesmo atrás de
um firewall — um bug local de escalação de privilégio num daemon que você
nunca usa ainda é um risco, e uma regra de firewall mal configurada depois
pode expor acidentalmente algo que você esqueceu que estava rodando. A
regra: se você não precisa, não rode.Faça o inventário do que está escutando e do que está habilitado
# O que está de fato escutando num socket de rede agora sudo ss -tulpn # Quais serviços estão habilitados para iniciar no boot systemctl list-unit-files --type=service --state=enabledNuma imagem Ubuntu server mínima, você tipicamente vai ver coisas como
cron,rsyslogesshd— mantenha essas. Fique atento a qualquer coisa
que você não instalou conscientemente: um agente de transporte de e-mail
não usado (exim4,postfix), um serviço de impressão (cups), ou um
banco de dados/serviço ligado a0.0.0.0que você nunca pretendeu expor
além dolocalhost.Desabilite o que você não precisa
# Exemplo: desabilita e para um serviço que você identificou como desnecessário sudo systemctl disable --now <nome-do-servico> # Confirme que sumiu de "enabled" e de "listening" systemctl is-enabled <nome-do-servico> # deve imprimir "disabled" ou erro sudo ss -tulpn | grep <nome-do-servico> # não deve imprimir nadaPara qualquer coisa ligada a
0.0.0.0que você precisa, mas só para uso
local (ex.: um banco de dados que você só consulta da mesma máquina),
religue-o para127.0.0.1na configuração dele em vez de depender só do
firewall — isso é defesa em profundidade: mesmo que uma regra de firewall
seja afrouxada por engano depois, o serviço ainda não vai aceitar conexões
remotas.Checkpoint
sudo ss -tulpnToda linha na saída deve ser algo que você consegue nomear e justificar.
Se você não consegue dizer por que um socket escutando existe, isso é a
próxima coisa a investigar e provavelmente desabilitar.Entregável deste passo: uma saída de
ss -tulpnonde todo socket
escutando é justificado, mais a lista de serviços que você desabilitou e o
motivo. -
Instale o fail2ban e verifique um banimento (submissão)
O
ufw limitdesacelera a força bruta; ofail2banbane ativamente um IP
infrator após falhas repetidas, observando seus logs e atualizando o
firewall por você. Esta é a última camada deste lab, e a que você vai provar
de ponta a ponta.Instale e habilite o jail de SSH
sudo apt-get install -y fail2ban sudo tee /etc/fail2ban/jail.local > /dev/null <<'EOF' [sshd] enabled = true port = 22 filter = sshd logpath = /var/log/auth.log maxretry = 3 findtime = 5m bantime = 15m EOF sudo systemctl enable --now fail2ban sudo systemctl status fail2ban --no-pagerDispare um banimento de verdade
Da sua máquina host, falhe deliberadamente o login SSH mais vezes que
maxretrycontra sua própria máquina descartável:for i in 1 2 3 4; do ssh -p 2222 -o PubkeyAuthentication=no -o PreferredAuthentications=password \ -o ConnectTimeout=3 opslab@localhost 'echo nao-deveria-chegar' || true doneVerifique que o banimento realmente entrou em vigor
sudo fail2ban-client status sshdVocê deve ver o IP da sua máquina (provavelmente
127.0.0.1ou o endereço
do gateway do Docker) listado em "Banned IP list". Confirme que uma
tentativa de conexão subsequente é recusada de cara (connection
refused/timeout, nem chega a pedir senha) até obantimepassar, ou desbaneie
manualmente para continuar trabalhando:sudo fail2ban-client set sshd unbanip <o-ip>
Critério de submissão
Submeta quando tudo o que segue for verdade, cada item respaldado pela
saída de comando que o comprova:-
Usuário sudo não-root —
sudo whoamifunciona comoopslaba partir
de um login novo (Passo 2). -
SSH só por chave, sem root — login por senha e login root ambos
falham; login por chave doopslabfunciona (Passo 3). -
Firewall negar-por-padrão —
sudo ufw status verbosemostradeny (incoming)com uma allowlist explícita e mínima (Passo 4). -
Superfície de serviços mínima — saída de
sudo ss -tulpncom todo
socket escutando justificado, e a lista de serviços que você desabilitou
(Passo 5). -
fail2ban funcionando —
sudo fail2ban-client status sshdmostrando
pelo menos um IP banido pelo seu próprio teste deliberado de login
falho (este passo).
Escreva uma nota curta sobre o que você adicionaria em seguida para uma
máquina de produção (ex.: atualizações automáticas de segurança via
unattended-upgrades, envio centralizado de logs, um agente de detecção de
intrusão) — você não precisa implementar, só nomear a próxima camada. -
Usuário sudo não-root —