A falsa sensação de segurança de "PermitRootLogin no"

É praticamente um mantra a ideia de que devemos colocar PermitRootLogin no em /etc/ssh/sshd_config em máquinas cujo servidor SSH fique exposto à internet. Até tem alguma utilidade se for usada autenticação por senha. "Alguma" pois não devemos jamais usar autenticação por senha! Mesmo que seja uma senha de 50 caracteres. Mais providências são requeridas para proteger minimamente o servidor.

Use autenticação por chave pública. Uma chave ssh-rsa de 2048 bits é impossível ser quebrada pelo menos até meados da próxima década. Até lá você troca a chave ou migra para uma de 4096 bits. Há debate considerável da necessidade ou não de chaves deste comprimento atualmente; estando em dúvida, caso o cliente suporte e o consumo maior de processamento não seja fator determinante, vá direto para 4096 bits. Resta, claro, uma falha de segurança no daemon sshd (ou no kernel ou glibc quem sabe), que permita um invasor comprometer o sistema. Mantenha tudo atualizado. A seguir, uso como base o CentOS 7.

Em /etc/ssh/sshd_config, primeiro certifique-se de que a versão 1 do protocolo SSH não está ativa. Para isso, remova ou comente a opção Protocol. Desde o OpenSSH 5.4 o protocolo 1 vem desativado (e no 7.0 nem é mais compilado). Para versões anteriores (arrrg!), coloque Protocol 2. Ou melhor: atualize sua distribuição!

UsePrivilegeSeparation sandbox deve ser usada sempre[1]. Foi introduzida no OpenSSH 5.9, adaptada para usar na versão 6.0 seccomp no Linux e vem habilitada por padrão desde a 6.1. Todo cuidado é pouco com arquivos de configuração remanescentes de instalações velhas. UsePAM yes é fundamental também, pois é como o daemon registra as sessões dos usuários no logind.

PubkeyAuthentication yes

Ativa a autenticação por chave pública. Então o mais importante:

PasswordAuthentication          no
ChallengeResponseAuthentication no
HostbasedAuthentication         no
GSSAPIAuthentication            no

Desativam os demais métodos.

Gere sua chave e coloque-a em ~/.ssh/authorized_keys. O diretório .ssh deve ser 0700 e o arquivo authorized_keys 0600, o usuário corrente sendo dono de ambos.

Existem vários tutoriais por aí discorrendo sobre os meandros da criação e configuração da chave e como conectar-se através do cliente ssh, ou do PuTTY.

O próximo passo é configurar um firewall na máquina e um programa para bloquear falhas de autenticação dos desgraçados que ficarão martelando seu servidor 24h por dia.

Usando o firewalld, comece configurando a interface externa como sendo da zona external. Jeito simples é adicionando ZONE=external no arquivo ifcfg correspondente em /etc/sysconfig/network-scripts. Essa zona permite acesso à porta TCP 22 e mais nada por padrão. O firewalld habilita masquerading na zona external. Desative caso achar adequado com:

# firewall-cmd --permanent --zone=external --remove-masquerade
# firewall-cmd --reload

Para conter os assédios externos, uma alternativa é o fail2ban, que está presente no repositório EPEL. Instale o pacote epel-release para habilitá-lo, e então fail2ban-firewalld, que faz a integração entre os dois programas e trata de puxar as dependências. Um simples /etc/fail2ban/jail.local dá conta do recado:

[DEFAULT]
bantime  = 172800
findtime = 1800
maxretry = 3

[sshd]
enabled = true

[sshd-ddos]
enabled = true

(man jail.conf para informações)

No momento, o pacote do fail2ban não obriga o firewalld estar rodando. A única dependência é uma ordenação After=. Isso é bug. Enquanto o pacote não for consertado, recomendo usar localmente:

# mkdir /etc/systemd/system/fail2ban.service.d

/etc/systemd/system/fail2ban.service.d/firewalld.conf

[Unit]
Requires=firewalld.service

# systemctl daemon-reload
# systemctl enable --now fail2ban.service

Acompanhe a quantas anda a lista de banimentos através de ipset list e /var/log/fail2ban.log.

Mudar a porta do servidor não me parece uma medida de segurança das mais eficazes. Ao fazê-lo, lembre de adicionar port = <número> em cada uma das seções relevantes de jail.local e ajustar as coisas no firewalld e SELinux. Exemplo (porta 2222):

# firewall-cmd --permanent --zone=external --remove-service=ssh
# firewall-cmd --permanent --zone=external --add-port=2222/tcp
# firewall-cmd --reload
# semanage port -a -t ssh_port_t -p tcp 2222

Não sou adepto de criar um usuário normal para administração. Porque a primeira coisa que precisarei fazer será recorrer a su -. Na Wiki da Mozilla, é dada como justificativa apenas dessa forma ser possível auditar sessões do root. Só que com o logind/auditd todas as sessões são registradas, sendo para mim um argumento fraco em distribuições modernas.

Mude PermitRootLogin para without-password, que proíbe o usuário root autenticar remotamente via senha e exige um dos outros métodos — tendo apenas PubkeyAuthentication habilitado, não fará muita diferença, contudo. Mesmo assim é uma boa configuração padrão. Restrinja, por fim, quem pode logar remotamente com AllowUsers, AllowGroups, DenyUsers, DenyGroups.


[1] A partir da versão 7.5, é mandatória e não precisa mais ser especificada.

Comentários