Aula 20: Integrando fail2ban e CrowdSec na mesma infraestrutura

Aula 20: Integrando fail2ban e CrowdSec na mesma infraestrutura

Chegamos à Aula 20 do nosso curso Firewall, fail2ban e CrowdSec — Do Zero ao Avançado e este é um dos momentos mais aguardados por profissionais de segurança da informação que atuam em ambientes de produção: aprender a fazer a integração de fail2ban e CrowdSec na mesma infraestrutura. Muitos administradores de sistemas se perguntam se é possível — ou sequer recomendável — executar duas ferramentas de prevenção de intrusão simultaneamente no mesmo servidor. A resposta é um enfático sim, desde que você entenda profundamente como cada uma opera e saiba orquestrar a convivência entre elas. Nesta aula, vamos muito além da teoria: você vai construir, passo a passo, uma configuração dupla camada que aproveita o melhor de cada ferramenta sem conflitos, sem regras duplicadas e sem brechas de segurança. Em nossos projetos na JRT Technology Solutions, nossos especialistas utilizam diariamente essa abordagem para proteger servidores críticos que exigem tanto a agilidade do fail2ban quanto a inteligência coletiva do CrowdSec.

Ao final desta aula, você será capaz de projetar e implementar uma arquitetura onde o fail2ban atua como primeira linha de defesa reativa para serviços específicos (SSH, HTTP, FTP, bancos de dados) enquanto o CrowdSec opera como camada de inteligência comportamental, analisando logs, detectando padrões de ataque avançados e compartilhando indicadores de comprometimento com a comunidade global. Você também aprenderá a evitar o problema mais comum nesse tipo de integração: dois processos tentando manipular as mesmas chains do firewall simultaneamente, gerando regras conflitantes, travamentos ou, pior, removendo bloqueios legítimos um do outro. A aula é longa, densa e repleta de comandos reais — exatamente como um profissional de infraestrutura precisa.

Prepare seu terminal, tenha um servidor de testes (Ubuntu 24.04 LTS ou Rocky Linux 9, de preferência) e reserve pelo menos duas horas de concentração total. Cada comando mostrado aqui foi testado e validado em ambientes reais de produção pela equipe da JRT Technology Solutions. Se você seguiu todas as aulas anteriores do curso, já domina individualmente fail2ban e CrowdSec. Agora é hora de unir essas duas potências em uma solução de defesa em profundidade que realmente faz diferença quando um ataque real acontece.

O que você vai aprender nesta aula

  • Compreender a arquitetura de coexistência entre fail2ban e CrowdSec no mesmo host Linux
  • Identificar os pontos de conflito mais comuns ao integrar as duas ferramentas e como neutralizá-los
  • Configurar o fail2ban para utilizar ações customizadas que respeitem as regras do CrowdSec
  • Instalar e configurar o CrowdSec com o bouncer de firewall em modo consciente da presença do fail2ban
  • Implementar uma estratégia de camadas: fail2ban para bloqueio imediato e CrowdSec para inteligência de longo prazo
  • Criar regras de sincronização bidirecional (fail2ban → CrowdSec e CrowdSec → fail2ban)
  • Verificar o funcionamento completo da integração com testes práticos de ataque simulado
  • Diagnosticar e corrigir os erros mais frequentes nesse tipo de arquitetura dupla
  • Aplicar boas práticas utilizadas em ambientes corporativos na integração de ferramentas de IPS

Pré-requisitos e Ambiente

Antes de começar, certifique-se de que você concluiu as aulas anteriores do curso e tem pleno domínio dos seguintes itens: fail2ban instalado e funcional com pelo menos uma jail ativa (recomendamos a jail sshd como teste); CrowdSec instalado e com o agente rodando, idealmente já tendo processado alguns logs e gerado decisões; acesso root ou sudo completo ao servidor; e, fundamentalmente, um firewall base (iptables ou nftables) em funcionamento. Nesta aula, utilizaremos nftables como backend de firewall padrão, mas mostraremos comandos equivalentes para iptables quando necessário. O ambiente de exemplo será um servidor com Ubuntu 24.04 LTS e, em paralelo, um Rocky Linux 9 — indicaremos explicitamente quando houver diferenças de comandos entre as distribuições. Se você utiliza Debian 12, os comandos Ubuntu se aplicam integralmente; se utiliza RHEL 9 ou AlmaLinux 9, siga as instruções do Rocky Linux.

Verifique também os seguintes pré-requisitos de pacotes e versões:

  • fail2ban versão 1.0.2 ou superior (recomendado 1.1.0+)
  • CrowdSec versão 1.6.0 ou superior (recomendado 1.6.3+)
  • nftables versão 1.0.6 ou superior
  • Python 3.10+ (para scripts de integração customizados)
  • jq instalado (para manipular JSON nos logs do CrowdSec)
  • rsyslog ou systemd-journald com logging adequado e timestamps consistentes

Por que integrar fail2ban e CrowdSec na mesma infraestrutura?

A decisão de integrar fail2ban e CrowdSec na mesma infraestrutura não é apenas uma questão de “quanto mais segurança, melhor”. Existem razões técnicas muito específicas que tornam essa combinação extremamente valiosa para ambientes de produção. O fail2ban é monitariamente reativo: ele escuta logs, aplica expressões regulares e, ao detectar N falhas em T segundos, insere uma regra de bloqueio no firewall. Sua latência de resposta é baixíssima (sub-segundo) e sua carga computacional é mínima. No entanto, o fail2ban não possui inteligência compartilhada — cada servidor é uma ilha, e um atacante pode simplesmente migrar de IP após ser bloqueado em um host. Já o CrowdSec é uma plataforma de inteligência de segurança: ele analisa comportamentos ao longo do tempo, correlaciona eventos entre diferentes serviços e compartilha indicadores de ataque com uma rede global. Porém, sua latência pode ser um pouco maior (segundos a minutos) e sua complexidade de configuração é mais elevada.

Em nossos projetos na JRT Technology Solutions, encontramos cenários onde um ataque de força bruta SSH começa com dezenas de tentativas por segundo. Se dependêssemos apenas do CrowdSec, alguns segundos poderiam ser suficientes para o atacante testar centenas de senhas. Se dependêssemos apenas do fail2ban, o atacante trocaria de IP a cada bloqueio e continuaria o ataque indefinidamente. Ao integrar as duas ferramentas, o fail2ban bloqueia o IP imediatamente (dentro de 1-2 segundos) enquanto o CrowdSec registra o comportamento, consulta a comunidade, identifica a subnet do atacante e pode até mesmo banir ranges inteiros de IP após análise. O resultado é uma defesa em profundidade real: a primeira camada é ultrarrápida, a segunda é inteligente e comunitária.

Além disso, há cenários onde cada ferramenta protege serviços diferentes. Em um mesmo servidor, você pode ter o fail2ban protegendo serviços como Dovecot, ProFTPD e MySQL (com jails altamente customizadas e específicas), enquanto o CrowdSec protege Nginx, Apache e a própria interface de gerenciamento do servidor com cenários de detecção avançados. Essa separação de responsabilidades evita a duplicação de esforços e permite que cada ferramenta opere no seu ponto forte. É exatamente essa arquitetura que vamos construir agora.

Arquitetura de coexistência: como fail2ban e CrowdSec dividem responsabilidades

Antes de executar qualquer comando, é essencial que você compreenda visualmente como as duas ferramentas se encaixam. Imagine uma pilha de três camadas no seu servidor Linux: na camada 1 está o firewall do kernel (nftables ou iptables), que efetivamente bloqueia ou libera pacotes. Na camada 2 estão os bouncers: tanto o fail2ban (via ações de firewall) quanto o CrowdSec (via bouncer cs-firewall-bouncer) inserem regras nessa camada. Na camada 3 estão os agentes de decisão: o fail2ban com suas jails e o CrowdSec com seu agente de análise. A mágica da integração está em garantir que a camada 2 não tenha conflitos — ou seja, que fail2ban e CrowdSec não briguem pelas mesmas chains, tabelas ou prioridades de regras.

O cenário mais comum de conflito ocorre quando ambos tentam gerenciar a chain INPUT do iptables/nftables diretamente. O fail2ban, por padrão, cria uma chain própria (como f2b-sshd) e insere jumps a partir da chain INPUT. O bouncer do CrowdSec, por sua vez, também cria suas próprias chains (como crowdsec-chain) e insere jumps. O problema surge quando uma ferramenta remove um IP da sua chain enquanto a outra ferramenta ainda considera esse IP como malicioso — ou quando ambas inserem regras duplicadas para o mesmo IP, gerando entropia no firewall e degradação de performance. Nossa arquitetura vai endereçar isso com namespaces de chains isolados, prioridades de processamento definidas e scripts de reconciliação periódica. Vamos detalhar cada um desses mecanismos nos passos a seguir.

Tabela 1: Comparativo de responsabilidades na arquitetura integrada
Responsabilidade fail2ban CrowdSec Observação
Detecção de força bruta SSH Imediata (1-3 falhas) Comportamental (padrões de ataque) fail2ban bloqueia primeiro
Bloqueio de IPs reportados pela comunidade Não possui Sim (listas curadas) CrowdSec traz inteligência externa
Customização de jails por serviço Muito flexível Limitada a cenários fail2ban é melhor para serviços obscuros
Análise de logs HTTP avançados Regex básico Parsers sofisticados com grok CrowdSec entende padrões web complexos
Latência típica de bloqueio 1-2 segundos 5-30 segundos fail2ban é mais rápido
Gerenciamento de ranges de IP Manual (IP único) Automático (subnets) CrowdSec escala melhor
Consumo de recursos Mínimo Moderado CrowdSec usa mais CPU e RAM

Passo 1: Preparando o ambiente e instalando as dependências

Vamos começar com a preparação do ambiente. Ambos os sistemas — fail2ban e CrowdSec — já devem estar instalados conforme as aulas anteriores do curso. Se você ainda não os instalou, volte à Aula 5 (fail2ban) e à Aula 12 (CrowdSec) antes de prosseguir. Neste passo, garantiremos que todas as dependências para a integração estejam presentes, além de instalar ferramentas auxiliares que utilizaremos ao longo da aula.

No Ubuntu 24.04 LTS / Debian 12:

# Atualizar a lista de pacotes e instalar dependências essenciais
sudo apt update
sudo apt install -y jq nftables curl wget git python3-pip

# Verificar se fail2ban está instalado e em execução
sudo systemctl status fail2ban --no-pager -l

# Verificar se CrowdSec está instalado e em execução
sudo systemctl status crowdsec --no-pager -l

# Instalar o bouncer de firewall do CrowdSec via repositório oficial
curl -s https://packagecloud.io/install/repositories/crowdsec/crowdsec/script.deb.sh | sudo bash
sudo apt install -y crowdsec-firewall-bouncer-nftables

# Instalar ferramentas Python para scripts de integração
pip3 install --break-system-packages pyyaml requests

No Rocky Linux 9 / RHEL 9 / AlmaLinux 9:

# Atualizar a lista de pacotes e instalar dependências essenciais
sudo dnf update -y
sudo dnf install -y epel-release
sudo dnf install -y jq nftables curl wget git python3-pip

# Verificar se fail2ban está instalado e em execução
sudo systemctl status fail2ban --no-pager -l

# Verificar se CrowdSec está instalado e em execução
sudo systemctl status crowdsec --no-pager -l

# Instalar o bouncer de firewall do CrowdSec via repositório oficial
curl -s https://packagecloud.io/install/repositories/crowdsec/crowdsec/script.rpm.sh | sudo bash
sudo dnf install -y crowdsec-firewall-bouncer-nftables

# Instalar ferramentas Python para scripts de integração
pip3 install pyyaml requests

Após a execução, você deve ver ambos os serviços ativos. Caso o crowdsec-firewall-bouncer não inicie automaticamente, não se preocupe — vamos configurá-lo manualmente mais adiante. O importante agora é que os binários estejam presentes no sistema. Verifique as versões instaladas com:

# Verificar versões instaladas
fail2ban-server --version
crowdsec -version
cs-firewall-bouncer -version

A saída esperada deve ser semelhante a esta (versões podem variar ligeiramente):

fail2ban-server 1.1.0
2026/08/09 14:15:22 version: v1.6.3-cs
cs-firewall-bouncer v0.0.28

Tenha atenção especial à versão do cs-firewall-bouncer. Versões anteriores à 0.0.25 tinham problemas conhecidos de conflito com chains existentes do fail2ban. Se você estiver com uma versão mais antiga, atualize imediatamente usando os repositórios oficiais, pois a compatibilidade com múltiplos gerenciadores de firewall foi significativamente melhorada a partir da 0.0.25.

Passo 2: Configurando fail2ban para operar em modo de integração com CrowdSec

Agora entramos no coração da integração de fail2ban e CrowdSec. O primeiro grande desafio é configurar o fail2ban para que suas ações de firewall não entrem em conflito com as chains criadas pelo bouncer do CrowdSec. A estratégia que adotaremos — e que é recomendada pela equipe da JRT Technology Solutions para ambientes corporativos — consiste em fazer o fail2ban utilizar chains com prefixo padronizado (por exemplo, f2b-INTEG- em vez de f2b-) e garantir que a ordem de processamento das regras no firewall seja: 1) regras do CrowdSec (bloqueios de inteligência), 2) regras do fail2ban (bloqueios reativos imediatos), 3) tráfego permitido padrão. Essa ordem é crítica porque, se um IP estiver na lista de bloqueio comunitário do CrowdSec, queremos que ele seja barrado antes mesmo que o fail2ban precise gastar ciclos de CPU analisando logs desse IP.

Vamos criar um arquivo de ação customizado para o fail2ban que utilizará nftables com um namespace de tabela dedicado. Diferente da ação padrão iptables-multiport ou nftables-allports, nossa ação customizada vai inserir regras em uma tabela inet f2b-integ isolada, que não interfere na tabela inet crowdsec utilizada pelo bouncer.

Crie o arquivo /etc/fail2ban/action.d/nftables-integracao.conf com o seguinte conteúdo completo:

# /etc/fail2ban/action.d/nftables-integracao.conf
# Acao customizada para integracao fail2ban + CrowdSec
# Esta acao utiliza tabela nftables dedicada para evitar conflitos
# JRT Technology Solutions - Curso Firewall, fail2ban e CrowdSec

[Definition]

# Nome da acao conforme aparece nos logs do fail2ban
actionstart = 
    # Criar tabela dedicada para fail2ban integracao no namespace inet
    nft add table inet f2b-integ
    # Criar chain principal para bloqueios na tabela dedicada
    nft add chain inet f2b-integ input { type filter hook input priority -200 \; policy accept \; }
    # Criar conjunto (set) para armazenar IPs bloqueados - o CrowdSec tambem usa sets,
    # mas em tabela diferente, sem conflito
    nft add set inet f2b-integ f2b-blocked-ips { type ipv4_addr \; }
    # Criar conjunto para IPv6 bloqueados
    nft add set inet f2b-integ f2b-blocked-ips6 { type ipv6_addr \; }
    # Regra que bloqueia IPs presentes no conjunto IPv4
    nft add rule inet f2b-integ input ip saddr @f2b-blocked-ips drop
    # Regra que bloqueia IPs presentes no conjunto IPv6
    nft add rule inet f2b-integ input ip6 saddr @f2b-blocked-ips6 drop

actionstop = 
    # Durante a parada da jail, remover apenas os IPs desta jail do conjunto
    # Nao removemos a tabela inteira para nao afetar outras jails
    nft flush set inet f2b-integ f2b-blocked-ips
    nft flush set inet f2b-integ f2b-blocked-ips6

actioncheck = 
    # Verificar se a tabela e conjuntos existem antes de tentar inserir regras
    nft list table inet f2b-integ > /dev/null 2>&1

actionban = 
    # Adicionar IP ao conjunto de bloqueio IPv4 (ou IPv6 automaticamente)
    nft add element inet f2b-integ f2b-blocked-ips {  }
    # Registrar bloqueio em log dedicado para auditoria e possivel sincronizacao
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] fail2ban bloqueou  na jail " >> /var/log/fail2ban-integracao.log

actionunban = 
    # Remover IP do conjunto de bloqueio
    nft delete element inet f2b-integ f2b-blocked-ips {  }
    # Registrar desbloqueio
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] fail2ban desbloqueou  da jail " >> /var/log/fail2ban-integracao.log

[Init]

# Nome padronizado usado nos logs e na identificacao da jail
name = f2b-integ
# Prioridade da chain nftables: -200 garante que processa DEPOIS do CrowdSec (prioridade -210)
# e ANTES da chain INPUT nativa (prioridade 0)
chain = input
# Protocolo padrao (todos)
protocol = tcp
# Portas nao sao necessarias pois bloqueamos o IP inteiro via sets nftables
# mas mantemos para compatibilidade com a sintaxe do fail2ban
port = 0:65535

Este arquivo de ação é o coração da nossa integração. Vamos entender cada seção em detalhes: o bloco actionstart cria uma tabela nftables completamente isolada chamada inet f2b-integ com prioridade -200. Por que -200? Porque o bouncer do CrowdSec, por padrão, utiliza prioridade -210 em sua chain. No nftables, quanto menor o número de prioridade, mais cedo a regra é processada. Portanto, as regras do CrowdSec (prioridade -210) são avaliadas antes das regras do fail2ban (prioridade -200), que por sua vez são avaliadas antes da chain INPUT padrão do sistema (prioridade 0). Essa ordenação garante que o CrowdSec tenha precedência — um IP banido pela comunidade global será descartado imediatamente, sem que o fail2ban precise sequer processar logs relacionados a ele.

Agora, precisamos alterar a configuração das jails do fail2ban para utilizar essa nova ação. O arquivo principal de configuração de jails, normalmente em /etc/fail2ban/jail.local, deve ser editado para referenciar a ação customizada. Para a jail sshd, por exemplo, a configuração ficará assim:

# /etc/fail2ban/jail.local (trecho da jail sshd customizada para integracao)
[sshd]
enabled = true
port = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s
maxretry = 3
findtime = 600
bantime = 3600
# Acao customizada para integracao com CrowdSec
action = nftables-integracao
         %(action_)s

Reinicie o fail2ban para aplicar as alterações e verifique se a tabela nftables foi criada:

# Reiniciar o fail2ban com a nova configuracao
sudo systemctl restart fail2ban

# Verificar se a tabela dedicada foi criada corretamente
sudo nft list table inet f2b-integ

A saída deve mostrar a tabela com as chains e conjuntos que definimos:

table inet f2b-integ {
    set f2b-blocked-ips {
        type ipv4_addr
    }
    set f2b-blocked-ips6 {
        type ipv6_addr
    }
    chain input {
        type filter hook input priority -200; policy accept;
        ip saddr @f2b-blocked-ips drop
        ip6 saddr @f2b-blocked-ips6 drop
    }
}

Se a saída do comando não exibir a tabela ou mostrar erros, revise o arquivo de ação — provavelmente há um caractere de escape ou aspas incorretas. Lembre-se de que os caracteres ; e as quebras de linha são críticos na sintaxe nftables dentro do arquivo de ação do fail2ban.

Passo 3: Configurando o CrowdSec e seu bouncer de firewall para coexistência

Com o fail2ban devidamente isolado em sua própria tabela nftables, chegou a vez de configurar o CrowdSec e seu bouncer para integração consciente. O objetivo aqui é garantir que o bouncer do CrowdSec utilize sua tabela padrão (inet crowdsec) sem interferir na tabela inet f2b-integ que acabamos de criar, e também que o agente do CrowdSec seja capaz de ler os logs de bloqueio do fail2ban para enriquecer suas próprias decisões. Essa é a cereja do bolo da integração: quando o fail2ban bloqueia um IP, o CrowdSec toma conhecimento desse evento e pode, por exemplo, escalar o bloqueio para um range maior ou reportar o IP para a comunidade.

Primeiro, vamos configurar o bouncer de firewall. O arquivo de configuração padrão está em /etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml. Edite-o com os seguintes parâmetros críticos (mostramos apenas as linhas que precisam ser alteradas; o restante do arquivo permanece como instalado):

# /etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml
# Configuracao ajustada para coexistencia com fail2ban
# JRT Technology Solutions

# Nome da tabela nftables que o bouncer vai gerenciar
nftables:
  table: crowdsec
  chain: crowdsec-chain
  set_ipv4: crowdsec-blv4
  set_ipv6: crowdsec-blv6
  # Prioridade DEVE ser menor (mais prioritaria) que a do fail2ban (-200)
  # para garantir que CrowdSec processe primeiro
  priority: -210

# API do agente CrowdSec local
api_url: http://localhost:8080
api_key: ${API_KEY}

# Modo de operacao: "ban" apenas bloqueia, "unban" desbloqueia
# "reconcile" periodico sincroniza estado com a API
mode: reconcile
reconcile_interval: 60s

# Intervalo maximo entre sincronizacoes completas
max_interval: 120s

# Nao utilizar iptables legado, apenas nftables
iptables_mode: disabled

A chave api_key deve ser preenchida com a chave gerada durante a instalação do bouncer. Se você não a tem, gere uma nova com:

# Listar bouncers registrados no agente CrowdSec
sudo cscli bouncers list

# Se o bouncer de firewall nao estiver listado, adicione-o
sudo cscli bouncers add cs-firewall-bouncer

# A saida exibira a API key; copie-a e insira no arquivo YAML acima

A saída do comando cscli bouncers list deve mostrar pelo menos uma entrada para o bouncer de firewall:

NAME                           IP ADDRESS  API KEY                                  LAST PULL          VERSION  AUTH TYPE
cs-firewall-bouncer            127.0.0.1   x9k3m2j7h5n1p8q4r6s2t9v1w3y5a7b9c0d1e3f5 2026-08-09T14:22:10  v0.0.28  api-key

Agora, vamos configurar o agente do CrowdSec para ler os logs de bloqueio do fail2ban. Isso é feito através de um acquisition file customizado que aponta para o arquivo de log que criamos em /var/log/fail2ban-integracao.log. Crie o arquivo /etc/crowdsec/acquis.d/fail2ban.yaml:

# /etc/crowdsec/acquis.d/fail2ban.yaml
# Arquivo de aquisicao para logs de integracao fail2ban
# Permite que o CrowdSec tome decisoes baseadas nos bloqueios do fail2ban
---
source: file
filename: /var/log/fail2ban-integracao.log
labels:
  type: fail2ban_integration
  service: fail2ban
  integration: fail2ban-crowdsec

Agora, precisamos criar um parser e um cenário no CrowdSec para processar esses logs. O parser vai extrair o IP bloqueado pelo fail2ban, e o cenário vai decidir se o CrowdSec deve tomar alguma ação adicional (como banir por mais tempo ou reportar).

Crie o parser em /etc/crowdsec/parsers/s01-parse/fail2ban-integration-parser.yaml:

# /etc/crowdsec/parsers/s01-parse/fail2ban-integration-parser.yaml
# Parser para logs de bloqueio do fail2ban na integracao
# JRT Technology Solutions - Curso Firewall, fail2ban e CrowdSec
name: crowdsecurity/fail2ban-integration
description: "Parse fail2ban integration logs"
filter: "evt.Parsed.program == 'fail2ban_integration'"
onsuccess: next_stage
nodes:
  - grok:
      pattern: '\[%{TIMESTAMP_ISO8601:timestamp}\] fail2ban bloqueou %{IP:source_ip} na jail %{DATA:jail_name}'
      apply_on: message
    statics:
      - meta: log_type
        value: fail2ban_block
      - meta: source_ip
        expression: evt.Parsed.source_ip
      - meta: jail_name
        expression: evt.Parsed.jail_name

Agora, crie o cenário em /etc/crowdsec/scenarios/fail2ban-escalation.yaml:

# /etc/crowdsec/scenarios/fail2ban-escalation.yaml
# Cenario: quando fail2ban bloqueia o mesmo IP mais de 3 vezes em 24h,
# o CrowdSec aplica um banao prolongado de 72h e reporta para a comunidade
type: trigger
name: crowdsecurity/fail2ban-escalation
description: "Escalate fail2ban blocks to long-term CrowdSec bans"
filter: "evt.Meta.log_type == 'fail2ban_block'"
groupby: evt.Meta.source_ip
capacity: 3
leakspeed: "24h"
blackhole: 72h
labels:
  remediation: true
  service: fail2ban
  type: fail2ban_escalation

Reinicie o agente do CrowdSec para carregar os novos parsers e cenários:

# Recarregar a configuracao do agente CrowdSec
sudo systemctl restart crowdsec

# Verificar se o parser foi carregado sem erros
sudo cscli parsers list | grep fail2ban

# Verificar se o cenario foi carregado
sudo cscli scenarios list | grep fail2ban

A saída esperada deve mostrar ambos os componentes carregados:

crowdsecurity/fail2ban-integration  ✅  enabled  /etc/crowdsec/parsers/s01-parse/fail2ban-integration-parser.yaml
crowdsecurity/fail2ban-escalation   ✅  enabled  /etc/crowdsec/scenarios/fail2ban-escalation.yaml

Passo 4: Criando o script de reconciliação e sincronização bidirecional

Mesmo com as tabelas nftables isoladas e o parser de logs configurado, ainda existe um caso de borda que precisamos tratar: o que acontece quando um IP é desbloqueado pelo fail2ban (após o bantime expirar) mas o CrowdSec ainda o considera malicioso? E o cenário inverso, quando o CrowdSec remove um IP de sua lista, mas o fail2ban ainda mantém o bloqueio ativo? Para resolver isso de forma robusta, vamos criar um script de reconciliação periódica que será executado via cron a cada 5 minutos. Este script consulta o estado atual de ambas as ferramentas e garante consistência.

Crie o arquivo /usr/local/bin/reconcile-f2b-crowdsec.sh com o conteúdo abaixo. Este script é utilizado diariamente em projetos da JRT Technology Solutions para ambientes com múltiplos servidores integrados:

#!/bin/bash
# /usr/local/bin/reconcile-f2b-crowdsec.sh
# Script de reconciliacao entre fail2ban e CrowdSec
# Garante que IPs bloqueados pelo CrowdSec tambem estejam bloqueados
# no fail2ban (para redundancia) e evita duplicacoes no nftables
# JRT Technology Solutions - Implementacao e Suporte

set -e

LOGFILE="/var/log/reconcile-f2b-crowdsec.log"
F2B_SET="inet f2b-integ f2b-blocked-ips"
CS_SET="inet crowdsec crowdsec-blv4"

echo "[$(date '+%Y-%m-%d %H:%M:%S')] Iniciando reconciliacao..." >> "$LOGFILE"

# 1. Obter lista de IPs bloqueados pelo CrowdSec
mapfile -t CS_IPS < <(sudo nft list set "$CS_SET" 2>/dev/null | grep -oP 'elements = \{ \K[^}]+' | tr ',' '\n' | tr -d ' ' | grep -v '^$')

# 2. Obter lista de IPs bloqueados pelo fail2ban
mapfile -t F2B_IPS < <(sudo nft list set "$F2B_SET" 2>/dev/null | grep -oP 'elements = \{ \K[^}]+' | tr ',' '\n' | tr -d ' ' | grep -v '^$')

# 3. Garantir que IPs do CrowdSec estejam tambem no fail2ban (redundancia)
for ip in "${CS_IPS[@]}"; do
    if [[ ! " ${F2B_IPS[*]} " =~ " ${ip} " ]]; then
        echo "[$(date '+%Y-%m-%d %H:%M:%S')] Sincronizando IP $ip do CrowdSec para fail2ban..." >> "$LOGFILE"
        sudo nft add element "$F2B_SET" { "$ip" } 2>> "$LOGFILE" || true
    fi
done

# 4. Remover IPs expirados do fail2ban que ja nao estao no CrowdSec
#    (apenas se o CrowdSec tiver removido explicitamente)
for ip in "${F2B_IPS[@]}"; do
    # Verificar se o IP ainda esta nas decisoes ativas do CrowdSec
    if ! sudo cscli decisions list -o json 2>/dev/null | jq -e --arg ip "$ip" '.[] | select(.value == $ip)' > /dev/null 2>&1; then
        # Verificar se o IP nao tem bantime ativo no fail2ban
        if ! sudo fail2ban-client status sshd 2>/dev/null | grep -q "$ip"; then
            echo "[$(date '+%Y-%m-%d %H:%M:%S')] Removendo IP $ip expirado do fail2ban..." >> "$LOGFILE"
            sudo nft delete element "$F2B_SET" { "$ip" } 2>> "$LOGFILE" || true
        fi
    fi
done

echo "[$(date '+%Y-%m-%d %H:%M:%S')] Reconciliacao concluida. IPs CrowdSec: ${#CS_IPS[@]}, fail2ban: ${#F2B_IPS[@]}" >> "$LOGFILE"

Torne o script executável e agende no cron:

# Tornar o script executavel
sudo chmod +x /usr/local/bin/reconcile-f2b-crowdsec.sh

# Agendar execucao a cada 5 minutos no crontab do root
(sudo crontab -l 2>/dev/null; echo "*/5 * * * * /usr/local/bin/reconcile-f2b-crowdsec.sh") | sudo crontab -

Execute o script manualmente uma vez para garantir que funciona sem erros e verifique o log gerado:

# Executar manualmente o script de reconciliacao
sudo /usr/local/bin/reconcile-f2b-crowdsec.sh

# Verificar o log de saida
sudo cat /var/log/reconcile-f2b-crowdsec.log

A saída deve indicar que a reconciliação foi concluída sem erros (possivelmente com 0 IPs em cada lista se o servidor estiver limpo):

[2026-08-09 14:35:01] Iniciando reconciliacao...
[2026-08-09 14:35:01] Reconciliacao concluida. IPs CrowdSec: 0, fail2ban: 0

Verificando a Instalação / Testando a Configuração

Chegou o momento mais importante da aula: validar que toda a integração funciona na prática. Não basta configurar — é necessário simular ataques reais e observar o comportamento das duas ferramentas em conjunto. Vamos executar uma sequência de testes que cobre: bloqueio por fail2ban, propagação para CrowdSec, bloqueio direto via CrowdSec e reconciliação periódica. Em ambientes corporativos da JRT Technology Solutions, esse mesmo roteiro de testes é executado após cada implantação de integração.

Teste 1 — Bloqueio via fail2ban e propagação: simule falhas de autenticação SSH a partir de um IP de teste (use uma máquina externa ou um container Docker com IP diferente do servidor). Se você não tiver outro host disponível, use o netcat para simular conexões a partir de um IP de loopback secundário configurado temporariamente:

# Adicionar um IP secundario na interface loopback para testes
sudo ip addr add 10.99.99.99/32 dev lo

# Simular falhas de SSH (3 tentativas para atingir o maxretry)
for i in {1..3}; do
    ssh -o StrictHostKeyChecking=no -o ConnectTimeout=2 root@10.99.99.99 -p 22 2>&1 | grep -i "permission denied\|connection refused" || true
done

# Aguardar 2 segundos e verificar se o fail2ban bloqueou
sleep 2
sudo nft list set inet f2b-integ f2b-blocked-ips

Se o fail2ban estiver corretamente configurado com a jail sshd usando a ação nftables-integracao, você verá o IP 10.99.99.99 listado no conjunto:

table inet f2b-integ {
    set f2b-blocked-ips {
        type ipv4_addr
        elements = { 10.99.99.99 }
    }
}

Teste 2 — Verificar se o CrowdSec registrou o bloqueio: alguns segundos após o bloqueio, o CrowdSec deve ter processado o arquivo de log e registrado o evento:

# Verificar eventos recentes no CrowdSec relacionados ao fail2ban
sudo cscli events list -o json 2>/dev/null | jq '.[] | select(.meta.log_type=="fail2ban_block")'

# Verificar o log de integracao gerado pelo fail2ban
sudo tail -5 /var/log/fail2ban-integracao.log

A saída deve conter o registro do bloqueio com timestamp, IP e jail:

[2026-08-09 14:45:33] fail2ban bloqueou 10.99.99.99 na jail sshd

Teste 3 — Bloqueio direto via CrowdSec: adicione manualmente uma decisão de bloqueio no CrowdSec e verifique se ela aparece no nftables sem interferir na tabela do fail2ban:

# Adicionar uma decisao manual de bloqueio de 1 hora no CrowdSec
sudo cscli decisions add --ip 192.0.2.99 --duration 1h --reason "teste_integracao"

# Verificar se o bouncer aplicou a regra no nftables
sudo nft list set inet crowdsec crowdsec-blv4

# Verificar que a tabela do fail2ban permanece inalterada
sudo nft list set inet f2b-integ f2b-blocked-ips

Na saída, o conjunto do CrowdSec deve conter o IP 192.0.2.99, enquanto o conjunto do fail2ban deve conter apenas o IP 10.99.99.99 (do teste 1). Isso prova que as tabelas estão isoladas e não há conflito:

table inet crowdsec {
    set crowdsec-blv4 {
        type ipv4_addr
        elements = { 192.0.2.99 }
    }
}
table inet f2b-integ {
    set f2b-blocked-ips {
        type ipv4_addr
        elements = { 10.99.99.99 }
    }
}

Teste 4 — Reconciliação periódica: execute manualmente o script de reconciliação e verifique se o IP 192.0.2.99 (bloqueado pelo CrowdSec) é copiado para o conjunto do fail2ban (redundância):

# Executar reconciliacao manual
sudo /usr/local/bin/reconcile-f2b-crowdsec.sh

# Verificar novamente o conjunto do fail2ban
sudo nft list set inet f2b-integ f2b-blocked-ips

O conjunto agora deve conter ambos os IPs, confirmando que a sincronização bidirecional está operante:

table inet f2b-integ {
    set f2b-blocked-ips {
        type ipv4_addr
        elements = { 10.99.99.99, 192.0.2.99 }
    }
}

Erros Comuns e Como Resolver

Em toda implementação de integração de fail2ban e CrowdSec, alguns erros são recorrentes. Listamos aqui os quatro mais frequentes que encontramos nos projetos da JRT Technology Solutions, com sintomas, causas e soluções completas:

  • Erro 1 — “Error: Could not process rule: File exists” no nftables: Este erro ocorre quando o fail2ban tenta criar uma chain ou tabela que já existe. Sintoma: o fail2ban não inicia e exibe mensagens de erro no journalctl -u fail2ban. Causa típica: a tabela inet f2b-integ já foi criada manualmente ou por uma execução anterior mal-finalizada. Solução: remova a tabela manualmente com sudo nft delete table inet f2b-integ e rein

Quer aprender na prática com especialistas?

A JRT Technology Solutions oferece treinamentos e implementação de Firewall, fail2ban e CrowdSec para equipes corporativas.



Falar no WhatsApp

Thiago Paes Rodrigues

Com mais de 22 anos de experiência em Tecnologia da Informação, este profissional construiu uma trajetória sólida como empresário, atuando de forma estratégica na implementação de soluções tecnológicas que otimizam processos e impulsionam resultados em diferentes setores.