Introdução
O SSH é o método padrão para conectar-se a um servidor na nuvem. É durável e extensível — à medida que novos padrões de criptografia são desenvolvidos, eles podem ser usados para gerar novas chaves SSH, garantindo que o protocolo central permaneça seguro. No entanto, nenhum protocolo ou pilha de software é totalmente infalível, e o fato de o SSH ser tão amplamente implantado na internet significa que ele representa uma superfície de ataque muito previsível, através da qual as pessoas podem tentar obter acesso.superfície de ataque ou vetor de ataque através do qual as pessoas podem tentar obter acesso.
Qualquer serviço exposto à rede é um alvo em potencial dessa maneira. Se você revisar os logs do seu serviço SSH em qualquer servidor com muito tráfego, frequentemente verá tentativas de login repetidas e sistemáticas que representam ataques de força bruta por usuários e bots. Embora você possa fazer algumas otimizações no seu serviço SSH para reduzir a chance desses ataques terem sucesso para próximo de zero, como desabilitar a autenticação por senha em favor das chaves SSH, eles ainda podem representar um pequeno passivo contínuo.
Implantações de produção em larga escala para as quais essa responsabilidade é completamente inaceitável geralmente implementarão uma VPN, como o WireGuard na frente de seu serviço SSH, para que seja impossível se conectar diretamente à porta SSH padrão 22 a partir da internet externa sem abstração ou gateways de software adicionais. Essas soluções de VPN são amplamente confiáveis, mas adicionam complexidade e podem quebrar algumas automações ou outros ganchos de software pequenos.
Antes de ou além de se comprometer com uma configuração de VPN completa, você pode implementar uma ferramenta chamada Fail2ban. O Fail2ban pode mitigar significativamente ataques de força bruta criando regras que automaticamente alteram a configuração do seu firewall para banir IPs específicos após um certo número de tentativas de login malsucedidas. Isso permitirá que seu servidor se proteja contra essas tentativas de acesso sem intervenção sua.
Em outro tutorial, discutimos Como proteger o SSH com Fail2ban. Neste guia, discutiremos mais detalhadamente como o Fail2ban realmente funciona e como você pode usar esse conhecimento para modificar ou estender o comportamento deste serviço.
Os Fundamentos do Fail2ban
O objetivo do Fail2ban é monitorar os logs de serviços comuns para identificar padrões em falhas de autenticação.
Quando o fail2ban está configurado para monitorar os registros de um serviço, ele examina um filtro que foi configurado especificamente para esse serviço. O filtro é projetado para identificar falhas de autenticação para esse serviço específico por meio do uso de expressões regulares complexas. Expressões regulares são uma linguagem de modelagem comum usada para correspondência de padrões. Ele define esses padrões de expressão regular em uma variável interna chamada failregex
.
Por padrão, o Fail2ban inclui arquivos de filtro para serviços comuns. Quando um registro de qualquer serviço, como um servidor web, corresponde ao failregex
em seu filtro, uma ação predefinida é executada para esse serviço. A ação
é uma variável que pode ser configurada para fazer muitas coisas diferentes, dependendo das preferências do administrador.
A ação padrão é banir o host/endereço IP ofensivo modificando as regras do firewall local. Você pode expandir essa ação para, por exemplo, enviar um e-mail para o administrador do sistema.
Por padrão, a ação será tomada quando três falhas de autenticação forem detectadas em 10 minutos, e o tempo de banimento padrão é de 10 minutos. Isso é configurável.
Ao usar o firewall padrão iptables
, o fail2ban
cria um novo conjunto de regras do firewall, também chamado de cadeia, quando o serviço é iniciado. Ele adiciona uma nova regra à cadeia INPUT que envia todo o tráfego TCP direcionado à porta 22 para a nova cadeia. Na nova cadeia, ele insere uma única regra que retorna para a cadeia INPUT. A cadeia e as regras associadas são removidas se o serviço Fail2ban for interrompido.
Explorando as Configurações do Serviço Fail2ban
O Fail2ban é configurado através de vários arquivos localizados em uma hierarquia sob o diretório /etc/fail2ban/
.
O arquivo fail2ban.conf
configura algumas configurações operacionais, como a maneira como o daemon registra informações, e o socket e o arquivo pid que ele usará. No entanto, a configuração principal é especificada nos arquivos que definem os “jails” por aplicação.
Por padrão, o fail2ban é fornecido com um arquivo jail.conf
. No entanto, este pode ser sobrescrito em atualizações, então você deve copiar este arquivo para um arquivo jail.local
e fazer ajustes lá.
Se você já tem um arquivo jail.local
, abra-o usando o nano
ou seu editor de texto favorito:
Se você ainda não tem um arquivo jail.local
, ou o arquivo que você abriu estava em branco, copie o arquivo jail.conf
e então abra o novo arquivo:
Vamos dar uma olhada nas opções disponíveis aqui e ver como este arquivo interage com outros arquivos de configuração no sistema.
A Seção Padrão
A primeira parte do arquivo definirá os padrões para a política do fail2ban. Essas opções podem ser substituídas em cada seção de configuração de serviço individual.
Sem os comentários, a seção padrão inteira se parece com isso:
[DEFAULT]
ignoreip = 127.0.0.1/8
bantime = 10m
findtime = 10m
maxretry = 3
backend = auto
usedns = warn
destemail = root@localhost
sendername = Fail2Ban
banaction = iptables-multiport
mta = sendmail
protocol = tcp
chain = INPUT
action_ = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
action_mw = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
%(mta)s-whois[name=%(__name__)s, dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s", sendername="%(sendername)s"]
action_mwl = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
%(mta)s-whois-lines[name=%(__name__)s, dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s", sendername="%(sendername)s"]
action = %(action_)s
Vamos analisar o que algumas dessas opções significam:
- ignoreip: Este parâmetro identifica os endereços IP que devem ser ignorados pelo sistema de banimento. Por padrão, isso é apenas configurado para ignorar o tráfego proveniente da própria máquina, para que você não preencha seus próprios logs ou se tranque para fora.
- bantime: Este parâmetro define o comprimento de um banimento, em segundos. O padrão é de 10 minutos.
- findtime: Este parâmetro define a janela na qual o Fail2ban prestará atenção ao procurar tentativas repetidas de autenticação malsucedidas. O padrão é definido como 10 minutos, o que significa que o software contará o número de tentativas falhadas nos últimos 10 minutos.
- maxretry: Isso define o número de tentativas falhadas que serão toleradas dentro da janela de
findtime
antes que um banimento seja instituído. - backend: Esta entrada especifica como o Fail2ban monitorará os arquivos de log. A configuração de
auto
significa que o fail2ban tentarápyinotify
, depoisgamin
, e depois um algoritmo de sondagem com base no que estiver disponível.inotify
é um recurso incorporado no kernel do Linux para rastrear quando os arquivos são acessados, epyinotify
é uma interface Python parainotify
, usada pelo Fail2ban. - usedns: Isso define se o DNS reverso é usado para ajudar a implementar proibições. Definir isso como “não” irá banir os IPs em si em vez de seus nomes de host de domínio. A configuração
warn
tentará procurar um nome de host e banirá dessa forma, mas registrará a atividade para revisão. - destemail: Este é o endereço para o qual será enviado o email de notificação se você configurar sua ação para enviar alertas por email.
- sendername: Isso será usado no campo de remetente do email para emails de notificação gerados
- banaction: Isso define a ação que será usada quando o limite for atingido. Na verdade, este é um caminho para um arquivo localizado em
/etc/fail2ban/action.d/
chamadoiptables-multiport.conf
. Isso lida com a manipulação real do firewalliptables
para banir um endereço IP. Veremos isso mais tarde. - mta: Este é o agente de transferência de correio que será usado para enviar emails de notificação.
- protocolo: Este é o tipo de tráfego que será descartado quando uma proibição de IP for implementada. Este também é o tipo de tráfego que é enviado para a nova cadeia iptables.
- chain: Esta é a cadeia que será configurada com uma regra de salto para enviar o tráfego para o funil do fail2ban.
Os demais parâmetros definem diferentes ações que podem ser especificadas. Eles passam alguns dos parâmetros que definimos acima usando substituição de variáveis dentro de cadeias de texto como esta:
%(nome_variavel)s
A linha acima seria substituída pelo conteúdo de var_name
. Usando isso, podemos dizer que a variável action
é definida por padrão como a definição action_
(somente banimento, sem alertas de email).
Isso, por sua vez, é configurado chamando a ação iptables-multiport
com uma lista de parâmetros (nome do serviço, porta, protocolo e cadeia) necessários para realizar o banimento. O __name__
é substituído pelo nome do serviço conforme especificado pelas seções abaixo.
Seções Específicas de Serviço
Abaixo da seção padrão, existem seções para serviços específicos que podem ser usadas para substituir as configurações padrão. Isso segue uma convenção de apenas modificar os parâmetros que diferem dos valores normais (convenção sobre configuração).
Cada cabeçalho de seção é especificado assim:
[nome_do_serviço]
Qualquer seção que tenha a linha enabled = true
será lida e habilitada.
Dentro de cada seção, os parâmetros são configurados, incluindo o arquivo de filtro que deve ser usado para analisar os logs (sem a extensão do arquivo) e a localização dos próprios arquivos de log.
Levando isso em consideração, a seção que especifica as ações para o serviço SSH parece com isso:
[SSH]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 6
Isso habilita esta seção e define a porta para a porta padrão “ssh” (porta 22). Diz ao Fail2ban para examinar o registro localizado em /var/log/auth.log
para esta seção e para analisar o registro usando os mecanismos de filtragem definidos no diretório /etc/fail2ban/filters.d
em um arquivo chamado sshd.conf
.
Todas as outras informações de que ele precisa são retiradas dos parâmetros definidos na seção [DEFAULT]
. Por exemplo, a ação será definida como action_
que banirá o endereço IP ofensivo usando a ação de banimento iptables-multiport
, que faz referência a um arquivo chamado iptables-multiport.conf
encontrado em /etc/fail2ban/action.d
.
Como pode ver, as ações na seção [DEFAULT]
devem ser gerais e flexíveis. Usar substituição de parâmetros junto com parâmetros que fornecem padrões sensíveis possibilitará a substituição de definições quando necessário.
Examinando o Arquivo de Filtro
Para entender o que está acontecendo em nossa configuração, precisamos entender os arquivos de filtro e de ação, que fazem a maior parte do trabalho.
O arquivo de filtro determinará as linhas que o fail2ban procurará nos arquivos de log para identificar características ofensivas. O arquivo de ação implementa todas as ações necessárias, desde a construção de uma estrutura de firewall quando o serviço é iniciado, até a adição e exclusão de regras, e a desmontagem da estrutura de firewall quando o serviço é interrompido.
Vamos dar uma olhada no arquivo de filtro que nosso serviço SSH solicitou na configuração acima:
[INCLUDES]
before = common.conf
[Definition]
_daemon = sshd
failregex = ^%(__prefix_line)s(?:error: PAM: )?[aA]uthentication (?:failure|error) for .* from <HOST>( via \S+)?\s*$
^%(__prefix_line)s(?:error: PAM: )?User not known to the underlying authentication module for .* from <HOST>\s*$
^%(__prefix_line)sFailed \S+ for .*? from <HOST>(?: port \d*)?(?: ssh\d*)?(: (ruser .*|(\S+ ID \S+ \(serial \d+\) CA )?\S+ %(__md5hex)s(, client user ".*", client host ".*")?))?\s*$
^%(__prefix_line)sROOT LOGIN REFUSED.* FROM <HOST>\s*$
^%(__prefix_line)s[iI](?:llegal|nvalid) user .* from <HOST>\s*$
^%(__prefix_line)sUser .+ from <HOST> not allowed because not listed in AllowUsers\s*$
^%(__prefix_line)sUser .+ from <HOST> not allowed because listed in DenyUsers\s*$
^%(__prefix_line)sUser .+ from <HOST> not allowed because not in any group\s*$
^%(__prefix_line)srefused connect from \S+ \(<HOST>\)\s*$
^%(__prefix_line)sUser .+ from <HOST> not allowed because a group is listed in DenyGroups\s*$
^%(__prefix_line)sUser .+ from <HOST> not allowed because none of user's groups are listed in AllowGroups\s*$
ignoreregex =
A seção [INCLUDES]
especifica outros arquivos de filtro que são lidos antes ou depois deste arquivo. Em nosso exemplo, o arquivo common.conf
é lido e colocado antes das outras linhas neste arquivo. Isso configura alguns parâmetros que estaremos usando em nossa configuração.
Em seguida, temos uma seção [Definition]
que define as regras reais para nossas correspondências de filtro. Primeiro, definimos o nome do daemon que estamos monitorando usando o parâmetro _daemon
.
Depois disso, passamos para a definição real de failregex
, que define os padrões que serão acionados quando uma linha correspondente no arquivo de log for encontrada. Estas são expressões regulares que correspondem com base nos diferentes erros e falhas que podem ocorrer quando um usuário não se autentica corretamente.
Partes da linha como %(__prefix_line)s
serão substituídas pelo valor de um parâmetro configurado no arquivo common.conf
que nós incluímos. Isso é usado para corresponder às diferentes informações iniciais que os sistemas operacionais escrevem nos arquivos de log quando usam métodos padrão. Por exemplo, algumas linhas do arquivo /var/log/auth.log
podem se parecer com isso:
May 6 18:18:52 localhost sshd[3534]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=101.79.130.213
May 6 18:18:54 localhost sshd[3534]: Failed password for invalid user phil from 101.79.130.213 port 38354 ssh2
May 6 18:18:54 localhost sshd[3534]: Received disconnect from 101.79.130.213: 11: Bye Bye [preauth]
A parte destacada é um padrão padrão que o sistema operacional insere para fornecer mais contexto. Depois disso, existem várias maneiras diferentes pelas quais o serviço de firewall iptables registra tentativas de falha no log.
Vemos duas falhas separadas nas duas primeiras linhas acima (um erro de autenticação PAM e um erro de senha). As expressões regulares definidas no filtro são projetadas para corresponder a qualquer uma das possíveis linhas de falha. Você não deve ajustar nenhuma dessas linhas, mas deve estar ciente da necessidade de capturar todas as entradas de log que indicam um erro de uso não autorizado para o aplicativo que está tentando proteger, se você precisar criar um arquivo de filtro você mesmo.
No final, você pode ver um parâmetro ignoreregex
, que está atualmente em branco. Isso pode ser usado para excluir padrões mais específicos que normalmente corresponderiam a uma condição de falha, caso você queira anular o gatilho de falha do fail2ban para certos cenários. Não vamos ajustar isso.
Salve e feche o arquivo quando terminar de examiná-lo.
Examinando o Arquivo de Ação
Agora, vamos dar uma olhada no arquivo de ação. Este arquivo é responsável por configurar o firewall com uma estrutura que permite modificações para banir hosts maliciosos e para adicionar e remover esses hosts conforme necessário.
A ação que nosso serviço SSH invoca é chamada iptables-multiport
. Abra o arquivo associado agora:
Com os comentários removidos, este arquivo parece algo assim:
[INCLUDES]
before = iptables-blocktype.conf
[Definition]
actionstart = iptables -N fail2ban-<name>
iptables -A fail2ban-<name> -j RETURN
iptables -I <chain> -p <protocol> -m multiport --dports <port> -j fail2ban-<name>
actionstop = iptables -D <chain> -p <protocol> -m multiport --dports <port> -j fail2ban-<name>
actioncheck = iptables -n -L <chain> | grep -a 'fail2ban-<name>[ \t]'
actionban = iptables -I fail2ban-<name> 1 -s <ip> -j <blocktype>
actionunban = iptables -D fail2ban-<name> -s <ip> -j <blocktype>
[Init]
name = default
port = ssh
protocol = tcp
chain = INPUT
O arquivo começa por importar outro arquivo de ação chamado iptables-blocktype.conf
que define o parâmetro blocktype
, que configura a restrição que será definida quando um cliente for banido. Por padrão, o blocktype
é configurado para rejeitar pacotes e responder aos pings enviados por clientes banidos com uma mensagem de rejeição informando que a porta é inacessível. Usaremos isso em nossas regras de banimento abaixo.
Em seguida, chegamos às definições de regra em si. A ação actionstart
configura o firewall iptables quando o serviço fail2ban é iniciado. Ele cria uma nova cadeia, adiciona uma regra a essa cadeia para retornar à cadeia de chamada e, em seguida, insere uma regra no início da cadeia INPUT que passa o tráfego correspondente aos protocolos e destinos de porta corretos para a nova cadeia.
Ele faz isso usando os valores que passamos com a ação
que definimos em nosso arquivo jail.local
. O nome
é retirado do cabeçalho de seção para cada serviço. O chain
, protocol
e porta
são retirados da própria linha de ação
nesse arquivo.
Aqui, todos os parâmetros que são definidos pelo outro arquivo são referenciados incluindo o nome do parâmetro entre colchetes angulares:
<nome_do_parametro>
Quando descemos para a definição de actionstop
complementar, podemos ver que os comandos do firewall estão implementando uma reversão dos comandos de actionstart
. Quando o serviço Fail2ban é encerrado, ele remove liminarmente quaisquer regras de firewall que tenha adicionado.
Outra ação chamada actioncheck
garante que a cadeia apropriada tenha sido criada antes de tentar adicionar regras de banimento.
Em seguida, chegamos à regra de banimento real, chamada actionban
. Esta regra funciona adicionando uma nova regra à nossa cadeia criada. A regra corresponde ao endereço IP de origem do cliente infrator – esse parâmetro é lido nos logs de autorização quando o limite de maxretry
é atingido. Ele institui o bloqueio definido pelo parâmetro blocktype
que obtivemos na seção [INCLUDE]
no topo do arquivo.
A regra actionunban
remove esta regra. Isso é feito automaticamente pelo fail2ban quando o tempo de banimento expira.
Finalmente, chegamos à seção [Init]
. Isso apenas fornece alguns valores padrão caso o arquivo de ação seja chamado sem passar todos os valores apropriados.
Como o Serviço Fail2ban Processa Arquivos de Configuração para Implementar Banimentos
Agora que vimos os detalhes específicos, vamos revisar o processo que acontece quando o fail2ban é iniciado.
Carregando os Arquivos de Configuração Iniciais
Primeiro, o arquivo principal fail2ban.conf
é lido para determinar as condições sob as quais o processo principal deve operar. Ele cria os arquivos de soquete, pid e log, se necessário, e começa a usá-los.
Em seguida, o fail2ban lê o arquivo jail.conf
para obter detalhes de configuração. Isso é seguido pela leitura, em ordem alfabética, de quaisquer arquivos encontrados no diretório jail.d
que terminem em .conf
. Ele adiciona as configurações encontradas nesses arquivos à sua configuração interna, dando preferência a novos valores sobre os valores descritos no arquivo jail.conf
.
Em seguida, ele procura por um arquivo jail.local
e repete esse processo, adaptando os novos valores. Por fim, ele pesquisa novamente o diretório jail.d
, lendo em ordem alfabética os arquivos que terminam em .local
.
No nosso caso, temos apenas um arquivo jail.conf
e um arquivo jail.local
. No nosso arquivo jail.local
, só precisamos definir os valores que diferem do arquivo jail.conf
. O processo fail2ban agora tem um conjunto de diretivas carregadas na memória que representam uma combinação de todos os arquivos que ele encontrou.
Ele examina cada seção e procura por uma diretiva enabled = true
. Se encontrar uma, usa os parâmetros definidos sob essa seção para construir uma política e decidir quais ações são necessárias. Quaisquer parâmetros que não sejam encontrados na seção do serviço usam os parâmetros definidos na seção [DEFAULT]
.
Analisando os Arquivos de Ação para Determinar as Ações Iniciais
O Fail2ban procura por uma diretiva action
para descobrir qual script de ação chamar para implementar as políticas de banimento/desbanimento. Se não encontrar um, recorre à ação padrão determinada acima.
A diretiva de ação consiste no nome do(s) arquivo(s) de ação que serão lidos, bem como em um dicionário chave-valor que passa os parâmetros necessários por esses arquivos. Os valores desses frequentemente assumem a forma de substituições de parâmetros referenciando as configurações configuradas na seção do serviço. A chave “nome” geralmente recebe o valor da variável especial __name__
que será definida com o valor do cabeçalho da seção.
O Fail2ban então usa essas informações para encontrar os arquivos associados no diretório action.d
. Primeiro, procura pelo arquivo de ação associado com a extensão .conf
e depois complementa as informações encontradas lá com quaisquer configurações contidas em um arquivo .local
acompanhante também encontrado no diretório action.d
.
Ele analisa esses arquivos para determinar as ações que precisa tomar. Ele lê o valor actionstart
para ver as ações que deve tomar para configurar o ambiente. Isso frequentemente inclui a criação de uma estrutura de firewall para acomodar regras de proibição no futuro.
As ações definidas neste arquivo utilizam os parâmetros passados para ele pela diretiva action
. Ele usará esses valores para criar dinamicamente as regras apropriadas. Se uma variável específica não foi definida, ele pode olhar para os valores padrão definidos no arquivo de ação para preencher as lacunas.
Analisando os Arquivos de Filtro para Determinar as Regras de Filtragem
Os parâmetros para o serviço nos arquivos jail.*
também incluem a localização do arquivo de log, bem como o mecanismo de sondagem que deve ser usado para verificar o arquivo (isso é definido pelo parâmetro backend
). Ele também inclui um filtro que deve ser usado para determinar se uma linha no log representa uma falha.
O Fail2ban procura no diretório filter.d
para encontrar o arquivo de filtro correspondente que termina com .conf
. Ele lê este arquivo para definir os padrões que podem ser usados para corresponder a linhas ofensivas. Em seguida, procura por um arquivo de filtro correspondente que termina com .local
para ver se algum dos parâmetros padrão foi sobrescrito.
Ele usa as expressões regulares definidas nesses arquivos enquanto lê o arquivo de log do serviço. Ele tenta cada linha failregex
definida nos arquivos filter.d
contra cada nova linha escrita no arquivo de log do serviço.
Se a expressão regular retornar uma correspondência, ela verifica a linha contra as expressões regulares definidas pelo ignoreregex
. Se também houver correspondência, o fail2ban ignora. Se a linha corresponder a uma expressão em failregex
, mas não corresponder a uma expressão em ignoreregex
, um contador interno é incrementado para o cliente que causou a linha e um timestamp associado é criado para o evento.
Ao atingir o intervalo de tempo definido pelo parâmetro findtime
nos arquivos jail.*
(conforme determinado pelo timestamp do evento), o contador interno é decrementado novamente e o evento não é mais considerado relevante para a política de banimento.
Se, ao longo do tempo, forem registradas falhas adicionais de autenticação, cada tentativa incrementa o contador. Se o contador atingir o valor definido pelo parâmetro maxretry
dentro do intervalo de tempo configurado, o fail2ban institui um banimento chamando a ação actioncheck
para o serviço conforme definido nos arquivos action.d/
para o serviço. Isso é para determinar se a ação actionstart
configurou a estrutura necessária. Em seguida, ele chama a ação actionban
para banir o cliente ofensivo. Ele também define um timestamp para este evento.
Quando o tempo especificado pelo parâmetro bantime
tiver decorrido, o fail2ban desbanirá o cliente chamando a ação actionunban
.
Conclusão
Neste ponto, você possui uma compreensão bastante profunda de como o fail2ban opera. Quando você se desvia da configuração padrão, é útil saber como o fail2ban funciona para manipular seu comportamento de maneira previsível.
Para aprender como proteger outros serviços com o fail2ban, você pode ler Como Proteger um Servidor Nginx com Fail2Ban no Ubuntu 22.04.