Linux Server Hardening Checklist 2026: SSH, Firewall, Kernel e Auditoria

Um servidor Linux acabado de instalar tem, por defeito, serviços a escutar em portas conhecidas, autenticação por palavra-passe sobre SSH, políticas de kernel permissivas e actualizações que dependem de intervenção manual. A combinação destes quatro pontos é o motivo pelo qual servidores expostos à Internet são comprometidos em horas — bots de varredura automatizada testam credenciais fracas e exploits públicos contra portas standard antes do primeiro dia de operação ter acabado (Arch Wiki — Security). A solução é uma checklist de hardening aplicada antes de o servidor entrar em produção: endurecer o SSH com chaves e porta não-standard, activar uma firewall com política de negação por defeito, configurar actualizações automáticas de segurança, activar controlo de acesso obrigatório (AppArmor ou SELinux), desactivar serviços desnecessários, instalar fail2ban contra brute-force, auditar com Lynis, aplicar parâmetros sysctl de hardening do kernel, desactivar IPv6 se não for usado, montar /dev/shm com noexec, e configurar rsyslog + logrotate para retenção e rotação de registos. Este artigo percorre as doze áreas, por ordem de impacto e complexidade, com comandos testados sintaticamente contra as man pages e wikis oficiais.

⚠ ⚠️ **Atenção

** Vários passos desta checklist (mudar a porta SSH, aplicar sysctl, montar /dev/shm com noexec, desactivar IPv6) podem quebrar serviços em produção se aplicados sem teste. Aplique primeiro num servidor de staging e confirme cada passo antes de avançar. Em servidores em produção, execute numa janela de manutenção com acesso de consola (out-of-band) garantido — perder acesso SSH por uma má configuração de firewall ou sshd_config é o cenário mais comum.

1. O que Está a Acontecer — A Superfície de Ataque de um Servidor Linux Recém-Instalado

Um servidor Linux recém-instalado (Ubuntu 24.04 LTS, Debian 12, RHEL 9, AlmaLinux 9, ou Rocky Linux 9) deixa a maior parte dos serviços numa configuração de “funciona por defeito”, não de “seguro por defeito”. Isto é uma decisão de usabilidade do upstream — os maintainers preferem que o servidor arranque e seja acessível, deixando o hardening para o operador (Arch Wiki — Security). A consequência directa é uma superfície de ataque que inclui:

  • SSH na porta 22 com autenticação por palavra-passe — a porta 22 é a primeira que bots automatizados testam. Dicionários de credenciais (root:root, admin:admin, ubuntu:ubuntu) são varridos em minutos contra qualquer IP público.
  • Login de root via SSH activo — se uma palavra-passe de root for fraca, o atacante obtém acesso administrativo imediato.
  • Serviços desnecessários a escutar em 0.0.0.0rpcbind, avahi-daemon, cups, postfix em modo default, dnsmasq, cada um é um vetor potencial.
  • Kernel com parâmetros permissivosnet.ipv4.ip_forward=1 se o servidor fizer routing, accept_redirects=1, icmp_echo_ignore_all=0. Cada um abre vetores de spoofing e amplificação.
  • Sem actualizações automáticas de segurança — o servidor fica vulnerável a CVEs publicados entre janelas de manutenção manuais.
  • Sem MAC (Mandatory Access Control) — AppArmor e SELinux vêm desactivados ou em modo permissivo em muitas instalações.
  • IPv6 activo mesmo sem utilização — abre uma segunda superfície de ataque se a firewall não cobrir IPv6.
  • /dev/shm montado com permissões de execução — usado historicamente para escalonamento de privilégios via exploits de memória partilhada.
  • Sem rotação de logs configuradajournald pode encher o disco; /var/log sem logrotate cresce indefinidamente.

O hardening não é uma única acção — é uma sequência de medidas que reduz a superfície de ataque em camadas: rede (firewall, IPv6), autenticação (SSH, fail2ban), kernel (sysctl), ficheiros (MAC, /dev/shm), actualizações (unattended-upgrades), e visibilidade (logs, auditoria Lynis). A ordem importa: a firewall deve ser aplicada antes de desactivar serviços (para evitar portas abertas durante a transição), e o SSH deve ser endurecido antes de expor o servidor à Internet.

2. Cenários em que Este Problema Aparece

  • VPS recém-provisionada (Hetzner, OVH, DigitalOcean, Linode, Vultr) — imagem standard Ubuntu/Debian/RHEL com SSH na porta 22 e palavra-passe de root. É o cenário mais comum e o mais atacado.
  • Servidor on-premise exposto à Internet — servidor web, mail, ou DNS num datacenter próprio, atrás de um router mas sem firewall de host configurada.
  • Servidor de staging com IP público — usado para testes antes de produção, mas acessível pela Internet durante semanas ou meses sem hardening.
  • Servidor pós-migração (on-premise → cloud) — a migração reinstala o SO ou usa uma imagem nova; o hardening do servidor antigo não é transportado automaticamente.
  • Servidor com kernel > 5.15 em distro recente — Ubuntu 24.04 (kernel 6.8), Debian 12 (6.1), RHEL 9 (5.14+). Parâmetros sysctl recomendados mudaram entre kernel 4.x e 6.x; usar guias antigos pode aplicar parâmetros obsoletos ou ineficazes.
  • Servidor com RHEL/Alma/Rocky em modo permissivo SELinux — instalação default de algumas imagens cloud deixa SELinux em permissive, o que regista violações mas não as bloqueia. Hardening efectivo requer enforcing.
  • Servidor Ubuntu/Debian com AppArmor em modo complain — mesmo padrão: regista mas não bloqueia. Verificar com aa-status.
  • Servidor exposto a brute-force SSH — sintomas: centenas de linhas Failed password em /var/log/auth.log ou journalctl -u sshd. Solução: fail2ban + key-only auth + porta não-standard.

3. Passo 1 — Endurecer o SSH (chaves, porta, sem root login)

O SSH é, em 90% dos servidores Linux expostos à Internet, o único serviço administrativo acessível. Endurecer o SSH é o passo de maior impacto individual na checklist. O ficheiro de configuração é /etc/ssh/sshd_config (man sshd_config(5), Arch Wiki — SSH). Os três parâmetros críticos são: PermitRootLogin no (desactiva login directo de root), PasswordAuthentication no (desactiva autenticação por palavra-passe, deixando apenas chaves), e Port (muda a porta standard 22 para outra, reduzindo o ruído de bots automatizados).

Antes de aplicar, gerar um par de chaves Ed25519 na máquina cliente (chaves RSA de 2048 bits são consideradas depreciadas; Ed25519 é o padrão recomendado pela Arch Wiki — SSH_keys):

# Gerar par de chaves Ed25519 na máquina cliente (não no servidor)
ssh-keygen -t ed25519 -a 100 -f ~/.ssh/servidor_producao -C “[email protected]
# -t ed25519: algoritmo EdDSA com chave Ed25519 (preferido sobre RSA)
# -a 100: 100 rounds de KDF (aumenta resistência a brute-force da chave privada)
# -f: ficheiro de saída (cria .pub automaticamente)
# -C: comentário para identificar a chave

Copiar a chave pública para o servidor (antes de desactivar autenticação por palavra-passe):

# Da máquina cliente para o servidor, usando a porta standard ainda
ssh-copy-id -i ~/.ssh/servidor_producao.pub -p 22 [email protected]
# -i: ficheiro de chave pública a instalar
# -p: porta SSH do servidor (22 neste passo; depois de mudar a porta, usar a nova)

Editar /etc/ssh/sshd_config no servidor (backup primeiro):

# Backup da configuração original
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.orig.$(date +%Y%m%d)# Parâmetros críticos a alterar (usar o editor preferido: nano, vim)
sudo nano /etc/ssh/sshd_config

Parâmetros a definir no ficheiro (descomentar e alterar os valores):

# Muda a porta SSH (exemplo: 2222). Reduz ruído de bots que varrem a porta 22.
Port 2222# Desactiva login directo de root via SSH.
# Para tarefas administrativas, usar sudo a partir de utilizador comum.
PermitRootLogin no

# Desactiva autenticação por palavra-passe. Só chaves SSH.
PasswordAuthentication no

# Desactiva autenticação por palavra-passe para todos os utilizadores (override de Match blocks).
KbdInteractiveAuthentication no

# Desactiva PAM se não for necessário (cuidado: pode quebrar auth LDAP/AD).
# UsePAM no # Descomentar apenas se souber o impacto.

# Limite de tentativas de autenticação por ligação
MaxAuthTries 3

# Tempo máximo de login não autenticado (30 segundos)
LoginGraceTime 30

# Desactiva encaminhamento X11 se não for necessário (reduz superfície)
X11Forwarding no

# Desactiva tunneling de dispositivos TCP se não for necessário
AllowTcpForwarding no

# Permite apenas utilizadores específicos (exemplo: admin, deploy)
AllowUsers admin deploy

Validar a configuração antes de reiniciar o serviço (crítico — evita perder acesso SSH):

# Testa a sintaxe do sshd_config sem reiniciar o serviço
sudo sshd -t
# Saída esperada: sem erros. Se houver erro, o comando mostra a linha problemática.# Se sshd -t passar, recarregar a configuração
sudo systemctl reload sshd
# Em distros que usam ‘ssh’ em vez de ‘ssh’ (Debian): sudo systemctl reload ssh

⚠️ Nunca fechar a sessão SSH actual antes de confirmar que a nova configuração funciona. Abrir uma segunda sessão SSH para a nova porta e confirmar que consegue autenticar com a chave. Só depois fechar a sessão original. Se não conseguir, reverter via consola do fornecedor (VPS) ou IPMI/KVM (on-premise).

4. Passo 2 — Activar a Firewall (ufw em Debian/Ubuntu, firewalld em RHEL, nftables avançado)

A firewall de host é a segunda camada de defesa. Política recomendada: negar tudo por defeito, permitir explicitamente apenas o necessário (Arch Wiki — Security#Firewall). Três ferramentas cobrem 95% dos casos: ufw (frente para iptables, simples, Ubuntu/Debian), firewalld (frente para nftables/iptables, RHEL/Alma/Rocky/Fedora), e nftables (framework nativo do kernel desde 3.13, substituto directo de iptables).

Via ufw (Ubuntu, Debian — recomendado para servidores simples)

# Instalar (se não estiver)
sudo apt update && sudo apt install -y ufw# Definir políticas default: negar incoming, permitir outgoing
sudo ufw default deny incoming
sudo ufw default allow outgoing

# Permitir SSH na nova porta (antes de activar a firewall!)
sudo ufw allow 2222/tcp comment ‘SSH admin’

# Se for servidor web, permitir HTTP e HTTPS
sudo ufw allow 80/tcp comment ‘HTTP’
sudo ufw allow 443/tcp comment ‘HTTPS’

# Se IPv6 estiver activo, garantir que ufw suporta IPv6 (default: sim em Ubuntu)
# Verificar /etc/default/ufw: IPV6=yes

# Activar a firewall
sudo ufw enable
# Saída esperada: “Firewall is active and enabled on system startup”

# Verificar estado e regras
sudo ufw status verbose
sudo ufw status numbered

Via firewalld (RHEL 9, AlmaLinux 9, Rocky Linux 9, Fedora)

# Instalar (se não estiver; em RHEL 9 vem por defeito)
sudo dnf install -y firewalld# Activar e arrancar o serviço
sudo systemctl enable –now firewalld

# Verificar estado
sudo firewall-cmd –state
# Saída esperada: running

# Verificar zona activa (default: public)
sudo firewall-cmd –get-default-zone
sudo firewall-cmd –get-active-zones

# Permitir SSH na nova porta (2222/tcp) permanentemente
sudo firewall-cmd –permanent –add-port=2222/tcp

# Servidor web: permitir HTTP e HTTPS
sudo firewall-cmd –permanent –add-service=http
sudo firewall-cmd –permanent –add-service=https

# Remover a regra SSH da porta 22 (que vem por defeito na zona public)
sudo firewall-cmd –permanent –remove-service=ssh

# Recarregar a configuração (aplica as mudanças permanentes)
sudo firewall-cmd –reload

# Listar tudo o que está configurado na zona activa
sudo firewall-cmd –list-all

Via nftables (avançado — substituto directo de iptables)

nftables é o successor do iptables, unificado para IPv4 e IPv6, com sintaxe mais limpa e melhor performance (wiki.nftables.org, Arch Wiki — Nftables).

# Instalar (se não estiver; em Debian 12 e Ubuntu 24.04 vem por defeito)
sudo apt install -y nftables# Ficheiro de configuração: /etc/nftables.conf
# Política default: deny incoming, allow outgoing, allow established/related
sudo nano /etc/nftables.conf

Configuração mínima de exemplo:

#!/usr/sbin/nft -fflush ruleset

table inet filter {
chain input {
type filter hook input priority 0; policy drop;

# Loopback
iif “lo” accept

# Estabelecidas e relacionadas
ct state established,related accept

# ICMP (rate-limit para evitar amplificação)
icmp type echo-request limit rate 5/second accept
ip6 nexthdr icmpv6 icmpv6 type echo-request limit rate 5/second accept

# SSH na porta 2222
tcp dport 2222 accept

# HTTP e HTTPS (se servidor web)
tcp dport { 80, 443 } accept
}

chain forward {
type filter hook forward priority 0; policy drop;
}

chain output {
type filter hook output priority 0; policy accept;
}
}

# Validar a sintaxe
sudo nft -c -f /etc/nftables.conf
# -c: check only (não aplica). Saída esperada: sem erros.# Aplicar
sudo nft -f /etc/nftables.conf

# Activar no arranque
sudo systemctl enable –now nftables

# Verificar regras activas
sudo nft list ruleset

5. Passo 3 — Activar Actualizações Automáticas de Segurança (unattended-upgrades)

As actualizações automáticas de segurança instalam patches de CVEs publicados sem intervenção manual. Para servidores estáveis que não correm workloads sensíveis a alterações de bibliotecas, é a diferença entre estar protegido contra um CVE crítico em horas e estar vulnerável durante semanas (Ubuntu Community — AutomaticSecurityUpdates, Debian — UnattendedUpgrades).

# Instalar em Debian/Ubuntu
sudo apt update && sudo apt install -y unattended-upgrades apt-listchanges# Configuração interactica (pergunta se quer activar auto-updates de segurança)
sudo dpkg-reconfigure -plow unattended-upgrades

# Para configurar manualmente, editar /etc/apt/apt.conf.d/50unattended-upgrades
sudo nano /etc/apt/apt.conf.d/50unattended-upgrades

Parâmetros a verificar/alterar em 50unattended-upgrades:

Unattended-Upgrade::Allowed-Origins {
“${distro_id}:${distro_codename}-security”;
“${distro_id}:${distro_codename}-security-updates”;
};// Reboot automático se necessário (cuidado em produção)
Unattended-Upgrade::Automatic-Reboot “false”;
// Se activar, definir janela:
Unattended-Upgrade::Automatic-Reboot-Time “04:00”;

// Email de alerta (requer mailx ou postfix configurado)
Unattended-Upgrade::Mail “[email protected]”;

// Remover dependências não usadas após upgrade
Unattended-Upgrade::Remove-Unused-Dependencies “true”;

// Lista de pacotes a NÃO actualizar automaticamente (ex: kernel, serviços críticos)
Unattended-Upgrade::Package-Blacklist {
// “linux-image”;
// “nginx”;
};

# Activar a execução automática (override do 10periodic)
sudo nano /etc/apt/apt.conf.d/10periodic
APT::Periodic::Update-Package-Lists “1”;
APT::Periodic::Download-Upgradeable-Packages “1”;
APT::Periodic::AutocleanInterval “7”;
APT::Periodic::Unattended-Upgrade “1”;
# Testar manualmente (dry-run)
sudo unattended-upgrade –dry-run -v# Forçar execução agora (sem esperar pelo cron)
sudo unattended-upgrade -v

# Verificar o que foi feito
sudo tail -f /var/log/unattended-upgrades/unattended-upgrades.log

⚠️ **Atenção

** em servidores com workloads sensíveis (bases de dados em produção, serviços com ABI rígido como Java com bibliotecas nativas), desactivar o reboot automático e a actualização automática de pacotes críticos (kernel, glibc, openssl). Um update de glibc pode quebrar binários compilados contra versões anteriores. Testar primeiro em staging.

6. Passo 4 — Activar AppArmor ou SELinux (Controlo de Acesso Obrigatório)

O MAC (Mandatory Access Control) é uma camada que restringe o que cada processo pode fazer, mesmo que tenha privilégios de root. AppArmor (Canonical, usado em Ubuntu/Debian/SUSE) e SELinux (NSA/Red Hat, usado em RHEL/Fedora/Alma/Rocky) são as duas implementações principais em Linux (Arch Wiki — Security#Mandatory_access_control, Red Hat — What is SELinux).

AppArmor (Ubuntu, Debian)

# Verificar estado
sudo aa-status
# Saída esperada: “apparmor module is loaded.” + lista de profiles carregados.# Se não estiver activo, instalar e activar
sudo apt install -y apparmor apparmor-utils
sudo systemctl enable –now apparmor

# Verificar profiles carregados e modo (enforce vs complain)
sudo aa-status | head -30

# Colocar um profile em modo enforce (bloqueia violações)
sudo aa-enforce /etc/apparmor.d/usr.sbin.nginx

# Colocar em modo complain (regista mas não bloqueia — útil para debug)
sudo aa-complain /etc/apparmor.d/usr.sbin.nginx

# Gerar profile para um binário sem profile (avançado)
sudo aa-genprof /usr/local/bin/meu_servico

SELinux (RHEL, Alma, Rocky, Fedora)

# Verificar estado
sudo getenforce
# Saída esperada: Enforcing, Permissive, ou Disabled# Verificar estado detalhado
sudo sestatus

# Activar enforcing (se estiver em permissive)
sudo setenforce 1

# Para persistir no arranque, editar /etc/selinux/config
sudo nano /etc/selinux/config

# Alterar de permissive/disabled para enforcing:
SELINUX=enforcing
SELINUXTYPE=targeted
# Se SELinux estiver disabled, é necessário relabel do sistema de ficheiros
# (demora; fazer em janela de manutenção)
sudo touch /.autorelabel
sudo reboot# Ver violações registadas (em permissive ou enforcing)
sudo ausearch -m AVC,USER_AVC,SELINUX_ERR -ts recent

# Ver contextos de ficheiros
ls -Z /var/www/html

# Alterar contexto de um ficheiro (ex: permitir que o Apache sirva conteúdo numa path não-standard)
sudo semanage fcontext -a -t httpd_sys_content_t “/meu_site(/.*)?”
sudo restorecon -Rv /meu_site

⚠️ Atenção: activar SELinux enforcing num servidor já em produção sem auditar primeiro em permissive pode quebrar serviços. Fluxo recomendado: (1) SELINUX=permissive, (2) operar durante 1-2 semanas recolhendo violações com ausearch, (3) ajustar políticas/booleans (setsebool -P httpd_can_network_connect 1), (4) só então SELINUX=enforcing. Idêntico para AppArmor: profiles novos em complain antes de enforce.

7. Passo 5 — Desactivar Serviços Desnecessários e Instalar fail2ban

Serviços desnecessários aumentam a superfície de ataque sem benefício. Listar o que está activo e a escutar:

# Listar sockets a escutar (TCP e UDP, IPv4 e IPv6)
sudo ss -tulnp
# -t: TCP, -u: UDP, -l: listening, -n: numérico, -p: processo# Alternativa: lsof
sudo lsof -i -P -n | grep LISTEN

# Listar serviços activos no systemd
sudo systemctl list-unit-files –type=service –state=enabled

# Desactivar serviços comuns desnecessários (avaliar caso a caso)
sudo systemctl disable –now rpcbind 2>/dev/null || true
sudo systemctl disable –now avahi-daemon 2>/dev/null || true
sudo systemctl disable –now cups 2>/dev/null || true
sudo systemctl disable –now modemmanager 2>/dev/null || true
sudo systemctl disable –now snapd 2>/dev/null || true

# Verificar o que ainda está a escutar depois de desactivar
sudo ss -tulnp

Instalar e configurar fail2ban contra brute-force SSH (Arch Wiki — Fail2ban, fail2ban no GitHub):

# Instalar
sudo apt install -y fail2ban # Debian/Ubuntu
sudo dnf install -y fail2ban # RHEL/Alma/Rocky# Criar override local (NÃO editar jail.conf directamente — perde-se em updates)
sudo nano /etc/fail2ban/jail.local

Configuração mínima de jail.local (adapta a porta SSH à nova porta):

[DEFAULT]
# Tempo de ban (1 hora)
bantime = 3600
# Janela de detecção (10 minutos)
findtime = 600
# Tentativas antes de banir
maxretry = 3
# Acção: ban via firewall (ufw ou firewalld conforme o backend)
banaction = ufw
# Em RHEL/Alma/Rocky: banaction = firewallcmd-ipset
# Email de alerta (opcional, requer mailx)
destemail = [email protected]
action = %(action_)s
%(action_mwl)s[sshd]
enabled = true
# Ajustar a porta à porta SSH configurada
port = 2222
# Backend de log: systemd em distros recentes, ficheiro em distros antigas
backend = systemd
# Para sistemas com /var/log/auth.log (Debian tradicional): backend = auto
logpath = %(sshd_log)s

# Activar e arrancar
sudo systemctl enable –now fail2ban# Verificar estado das jails
sudo fail2ban-client status
# Saída esperada: “Jail list: sshd”

# Verificar detalhe da jail sshd
sudo fail2ban-client status sshd
# Mostra: bans actuais, IPs banidos, tentativas registadas

# Ver logs do fail2ban
sudo journalctl -u fail2ban -f
# Em distros sem systemd para este log: sudo tail -f /var/log/fail2ban.log

8. Passo 6 — Hardening do Kernel com sysctl, Desactivar IPv6, Secure /dev/shm

Os parâmetros sysctl controlam o comportamento do kernel em runtime. Valores seguros reduzem a superfície de ataque ao nível da pilha de rede e do kernel (man sysctl(8), Arch Wiki — Sysctl#Security).

# Ver valor actual de um parâmetro
sudo sysctl net.ipv4.ip_forward
sudo sysctl net.ipv4.conf.all.send_redirects# Criar ficheiro de hardening (não editar /etc/sysctl.conf directamente)
sudo nano /etc/sysctl.d/99-hardening.conf

Configuração recomendada (kernel 5.14+ / 6.x, comentada para clarificar impacto):

# — IPv4 —# Desactiva forwarding de pacotes (se o servidor NÃO for router/gateway)
net.ipv4.ip_forward = 0

# Desactiva envio de ICMP redirects (evita spoofing de rotas)
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0

# Desactiva aceitação de ICMP redirects (evita MITM)
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0

# Desactiva aceitação de source routing (evita bypass de rotas)
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0

# Activar reverse path filtering (anti-spoofing)
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

# Ignorar pings broadcast (evita amplificação smurf)
net.ipv4.icmp_echo_ignore_broadcasts = 1

# Activar syncookies (mitiga SYN flood)
net.ipv4.tcp_syncookies = 1

# Limitar informações de rede expostas
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1

# — IPv6 —
# Se IPv6 NÃO for usado (ver passo seguinte), desactivar completamente:
# net.ipv6.conf.all.disable_ipv6 = 1
# net.ipv6.conf.default.disable_ipv6 = 1
# net.ipv6.conf.lo.disable_ipv6 = 1

# Se IPv6 for usado, pelo menos endurecer:
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_source_route = 0
net.ipv6.conf.default.accept_source_route = 0

# — Kernel —

# Desactiva core dumps em processos setuid (evita leaks de memória privilegiada)
fs.suid_dumpable = 0

# Activar execshield-equivalent (ASLR)
kernel.randomize_va_space = 2

# Limitar kernel pointer leaks via /proc/kallsyms
kernel.kptr_restrict = 2

# Desactiva kexec (evita boot de kernel malicioso em runtime)
kernel.kexec_load_disabled = 1

# Restringe acesso a dmesg a root (evita leaks de informação)
kernel.dmesg_restrict = 1

# Restringe acesso a /proc/ a processos do próprio utilizador
kernel.yama.ptrace_scope = 1

# Desactiva o módulo BPF não privilegiado (evita JIT spray)
kernel.unprivileged_bpf_disabled = 1
net.core.bpf_jit_harden = 2

# Aplicar as mudanças (sem reboot)
sudo sysctl –system
# –system: lê todos os ficheiros em /etc/sysctl.d/ por ordem# Verificar um parâmetro aplicado
sudo sysctl kernel.randomize_va_space
# Saída esperada: kernel.randomize_va_space = 2

Desactivar IPv6 se não for usado

Se o servidor não utiliza IPv6 (sem serviço a escutar em IPv6, sem rota IPv6), desactivar reduz a superfície de ataque (Arch Wiki — Security#Disable_IPv6).

# Verificar se IPv6 está activo
sudo sysctl net.ipv6.conf.all.disable_ipv6
# Saída esperada: 0 (activo) ou 1 (desactivado)# Verificar se algum serviço está a escutar em IPv6
sudo ss -tlnp6
# Se não houver serviços IPv6 e IPv6 não for necessário, desactivar

Adicionar ao ficheiro /etc/sysctl.d/99-hardening.conf (acima):

net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
sudo sysctl –system
# Verificar
ip -6 addr
# Saída esperada: sem endereços IPv6 listados

Secure shared memory (/dev/shm)

/dev/shm (memória partilhada POSIX) é, por defeito, montado com permissões que permitem execução de binários aí colocados. Em servidores endurecidos, montar com noexec, nosuid, nodev evita que exploits usem shm para execução de payloads (Arch Wiki — Security).

# Verificar a montagem actual
mount | grep shm
# Saída típica: tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)# Editar /etc/fstab
sudo nano /etc/fstab

Adicionar a linha (ou alterar a existente):

tmpfs /dev/shm tmpfs defaults,nodev,nosuid,noexec 0 0
# Remontar com as novas opções
sudo mount -o remount /dev/shm# Verificar
mount | grep shm
# Saída esperada: tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev,noexec)

9. Passo 7 — Auditar com Lynis e Configurar rsyslog + logrotate

Auditar o sistema com Lynis

Lynis é a ferramenta de auditoria de hardening mais usada em Linux, open-source, mantida pela CISOfy (cisofy.com/lynis, Lynis no GitHub). Corre uma auditoria de 400+ verificações (configuração SSH, firewall, kernel, permissões de ficheiros, serviços desnecessários) e produz um relatório accionável com um score de hardening.

# Instalar (Debian/Ubuntu)
sudo apt install -y lynis# Instalar (RHEL/Alma/Rocky via EPEL)
sudo dnf install -y epel-release && sudo dnf install -y lynis

# Verificar versão
lynis show version

# Auditar o sistema (corre como root)
sudo lynis audit system

# Para auditoria não-interactiva (scripting)
sudo lynis audit system –quiet

# Ver o relatório
sudo less /var/log/lynis-report.dat
sudo less /var/log/lynis.log

# Ver apenas os warnings
sudo grep Warning /var/log/lynis-report.dat

# Ver sugestões
sudo grep Suggestion /var/log/lynis-report.dat

# Ver hardening index (score 0-100)
sudo grep hardening_index /var/log/lynis-report.dat
# Saída esperada: hardening_index=XX (típico inicial: 60-70; após hardening: 80+)

Comparar o resultado do Lynis contra os CIS Benchmarks (recomendados para servidores em ambientes regulados — NIS2, PCI-DSS, ISO 27001). Os Benchmarks são pagos para download comercial, mas a versão community é gratuita mediante registo.

Configurar rsyslog para centralização e retenção

rsyslog é o daemon de syslog default em Ubuntu, Debian, RHEL, Alma, Rocky (Arch Wiki — Rsyslog). Verificar que está activo:

# Verificar estado
sudo systemctl status rsyslog# Se não estiver activo
sudo apt install -y rsyslog # Debian/Ubuntu
sudo dnf install -y rsyslog # RHEL
sudo systemctl enable –now rsyslog

# Verificar que está a receber logs
sudo journalctl -u rsyslog -n 20
# Em distros sem systemd para syslog: tail -f /var/log/syslog (Debian) ou /var/log/messages (RHEL)

Para enviar logs para um servidor central (recomendado em ambientes com múltiplos servidores):

# Editar /etc/rsyslog.conf ou criar /etc/rsyslog.d/99-remote.conf
sudo nano /etc/rsyslog.d/99-remote.conf
# Enviar todos os logs via TCP (mais fiável que UDP) para o servidor central
*.* @@logs-central.exemplo.pt:514# Para UDP (mais leve, sem garantia de entrega):
# *.* @logs-central.exemplo.pt:514

# Filtrar e enviar apenas auth logs (para SIEM):
auth,authpriv.* @@logs-central.exemplo.pt:514

# Validar a sintaxe
sudo rsyslogd -N1
# Saída esperada: rsyslogd: End of config validation. Bye.# Recarregar
sudo systemctl reload rsyslog

Configurar logrotate para rotação e retenção

logrotate rota, comprime e remove logs antigos, evitando que /var/log encha o disco (man logrotate(8), Arch Wiki — Logrotate).

# Verificar que está instalado
sudo apt install -y logrotate # Debian/Ubuntu
sudo dnf install -y logrotate # RHEL/Alma/Rocky# Verificar o ficheiro principal
sudo cat /etc/logrotate.conf | head -30

# Verificar os drops-ins específicos
ls /etc/logrotate.d/
# Típicos: apache2, nginx, mysql, syslog, rsyslog

# Testar a rotação manualmente (debug, sem aplicar)
sudo logrotate -d /etc/logrotate.conf
# -d: debug mode (não executa, só simula)

# Forçar a rotação
sudo logrotate -f /etc/logrotate.conf
# -f: force (rota mesmo que não esteja na altura)

Para criar uma política para um log de aplicação custom:

sudo nano /etc/logrotate.d/meu_app
/var/log/meu_app/*.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
create 0640 www-data adm
postrotate
systemctl reload meu_app 2>/dev/null || true
endscript
}
# Validar
sudo logrotate -d /etc/logrotate.d/meu_app

10. Passo 8 — Verificação Final e Manutenção Contínua

Depois de aplicar todos os passos anteriores, verificar que o servidor está endurecido:

# 1. Confirmar que só serviços necessários estão a escutar
sudo ss -tulnp# 2. Confirmar estado da firewall
sudo ufw status verbose # Debian/Ubuntu
sudo firewall-cmd –list-all # RHEL/Alma/Rocky
sudo nft list ruleset # nftables

# 3. Confirmar SSH
sudo sshd -T | grep -iE ‘permitrootlogin|passwordauthentication|port|maxauthtries’
# Saída esperada: port 2222, permitrootlogin no, passwordauthentication no, maxauthtries 3

# 4. Confirmar actualizações automáticas
sudo systemctl status apt-daily-upgrade.timer # Debian/Ubuntu
sudo systemctl status dnf-automatic.timer # RHEL/Alma/Rocky

# 5. Confirmar MAC
sudo aa-status | head -5 # AppArmor
sudo getenforce # SELinux

# 6. Confirmar fail2ban
sudo fail2ban-client status

# 7. Confirmar sysctl
sudo sysctl –system 2>&1 | tail -5
sudo sysctl net.ipv4.ip_forward
sudo sysctl kernel.randomize_va_space

# 8. Confirmar IPv6
sudo sysctl net.ipv6.conf.all.disable_ipv6

# 9. Confirmar /dev/shm
mount | grep shm

# 10. Confirmar Lynis score
sudo lynis audit system –quiet
sudo grep hardening_index /var/log/lynis-report.dat

Para manutenção contínua:

  • Correr sudo lynis audit system mensalmente e rever os warnings.
  • Subscrever a security mailing list da distro (debian-security-announce, ubuntu-security-announce, rhsa-announce da Red Hat).
  • Rever journalctl -u fail2ban semanalmente para identificar IPs recorrentes — considerar bloqueios permanentes se houver IPs persistentes.
  • Auditar os logs com journalctl --since "1 week ago" | grep -iE 'failed|denied|error' semanalmente.
  • Após cada major upgrade do SO (ex: Ubuntu 24.04 → 26.04), reauditar com Lynis e revalidar sysctl (parâmetros mudam entre kernels).

11. Outras Causas de Compromisso Num Servidor Linux

O hardening cobre a maior parte dos vectores comuns, mas não substitui medidas adjacentes. Se o servidor foi comprometido mesmo após esta checklist, considerar:

  • Aplicação web vulnerável (ex: WordPress desactualizado, plugin PHP com RCE conhecido) — o hardening do SO não protege contra vulnerabilidades na camada de aplicação. Ver: kbase.pt — Remover malware do computador para resposta a incidentes.
  • Palavras-passe fracas em serviços não-SSH (bases de dados, painéis admin, FTP) — usar palavra-passe forte única por serviço. Ver: kbase.pt — Definir palavra-passe segura.
  • Certificados SSL/TLS mal configurados ou ausentes — permitir tráfego HTTP em claro expõe credenciais em trânsito. Ver: kbase.pt — Redireccionar HTTP para HTTPS automaticamente.
  • Vulnerabilidades em dependências de aplicação (npm, pip, Composer, gems) — usar npm audit, pip-audit, composer audit, ou ferramentas como Trivy/Snyk no pipeline CI.
  • Falta de monitorização (sem SIEM, sem alertas) — hardening sem monitorização é defesa passiva. Configurar alertas para logins fora de horas, escaladas de privilégios, novos serviços a escutar.
  • Servidor em rede sem segmentação — se todos os servidores estão na mesma VLAN, comprometer um é comprometer todos. Segmentar com VLANs e firewalls entre zonas.

12. Como Evitar Compromisso Futuro

  • Aplicar a checklist antes de expor o servidor à Internet — nunca pôr um servidor em produção sem hardening prévio. Se for inevitável, expor atrás de uma firewall que só permite SSH a partir de IPs autorizados.
  • Manter um servidor de staging idêntico ao de produção (mesmo SO, mesma versão de kernel, mesma configuração de serviços). Testar todas as mudanças de hardening em staging primeiro.
  • Documentar cada alteração num changelog (Git, Ansible playbook, ou ficheiro de texto versionado). Isto permite reverter rapidamente e reproduzir a configuração em novos servidores.
  • Usar gestão de configuração (Ansible, Puppet, Chef) para aplicar a checklist de forma reprodutível. Hardening manual é propenso a esquecimentos.
  • Auditar com Lynis mensalmente e depois de cada major upgrade. O score deve manter-se acima de 80.
  • Manter chaves SSH rotativas — gerar chaves novas anualmente e revogar as antigas. Usar ssh-agent com IdentitiesOnly yes em ~/.ssh/config para evitar leakage de chaves.
  • Subscrever alertas CVE das bibliotecas e serviços críticos (NVD, vendor security mailing lists). Para servidores em ambientes regulados (NIS2), o relatório de incidente é obrigatório — ver kbase.pt — Relatório de incidente de cibersegurança.
  • Backups testados e offline — hardening não substitui backups. Se o servidor for comprometido, a recuperação rápida depende de um backup limpo e testado. Testar restauração trimestralmente.

 

Checklist Antes de Aplicar em Produção

Antes de aplicar qualquer comando deste artigo em ambiente produtivo, confirma:

  1. Versão do SO (Ubuntu 24.04+, Debian 12+, RHEL 9+, ou equivalente): cat /etc/os-release
  2. Versão do kernel (deve ser 5.14+; abaixo disso, alguns parâmetros sysctl podem não existir): uname -r
  3. Versão do OpenSSH (deve ser 8.2+ para KbdInteractiveAuthentication; 8.0+ para Ed25519 completo): sshd -V && ssh -V
  4. MAC disponível (AppArmor em Ubuntu/Debian, SELinux em RHEL/Alma/Rocky): aa-status 2>/dev/null || getenforce 2>/dev/null
  5. Staging environment disponível (VM idêntica, cloud snapshot, ou servidor de testes) para testar TODOS os passos antes de aplicar em produção. Em especial: mudança de porta SSH, sysctl --system, noexec em /dev/shm, SELinux enforcing.
  6. Backup do estado antes de aplicar mudanças: snapshot de VM, backup de /etc/ssh/sshd_config, /etc/sysctl.d/, /etc/fstab, /etc/fail2ban/jail.local, /etc/apt/apt.conf.d/. Comando: sudo tar -czf ~/hardening-backup-$(date +%Y%m%d).tar.gz /etc/ssh/ /etc/sysctl.d/ /etc/fail2ban/ /etc/rsyslog.d/ /etc/logrotate.d/

Artigos Relacionados