implant firewall
Wrapper sobre ufw com validação de IP/CIDR e portas, pensado tanto
para uso manual quanto para automação (ex.: um console de gerenciamento
remoto aplicando regras via --output json).
Uso
implant firewall <subcomando> [OPTIONS]Subcomandos
`allow --port [--proto tcp|udp] [--from ]`
Libera uma porta. Default: tcp. Com --from, restringe a origem
(ex.: --from 10.8.0.0/24).
`deny --port [--proto tcp|udp] [--from ]`
Bloqueia uma porta (opcionalmente só para uma origem). Com --from, o
DENY entra no topo das regras do UFW, como no block-ip (abaixo). Sem
--from, segue o comportamento do ufw deny (troca a ação de um allow
idêntico).
`block-ip `
Bloqueia todo o tráfego de um IP (v4 ou v6). O endereço é validado antes
de chamar ufw — entradas com newline, espaço ou metacaracteres são
recusadas.
Desde a v2.59.0, o DENY entra no topo da família do endereço, antes dos
allow de porta. Antes ele ia para o fim da lista, depois dos
allow 22/80/443, e o IP "bloqueado" continuava recebendo SSH e HTTP.
- IPv4:
ufw insert 1 deny from <IP>. - IPv6:
ufw insert <N> deny from <IP>, com N = posição da primeira regra v6 (o ufw numera todas as regras v4 antes das v6 e não aceitainsert 1para regra v6). - Sem nenhuma regra da família, é o append de sempre (que já é o topo dela).
- Uma regra igual que já exista (por exemplo, deixada no fim por versão anterior) é apagada e reinserida no topo.
- Com o UFW inativo, a regra é gravada e o comando avisa que ela só vale
depois do
enable.
$ sudo ufw status numbered
[ 1] Anywhere DENY IN 203.0.113.50
[ 2] 22/tcp ALLOW IN Anywhere
[ 3] 443/tcp ALLOW IN Anywhere
[ 4] Anywhere (v6) DENY IN 2001:db8::50
[ 5] 22/tcp (v6) ALLOW IN Anywhere (v6)
[ 6] 443/tcp (v6) ALLOW IN Anywhere (v6)
`unblock-ip `
Remove todas as regras deny de origem que o implant cria para o IP,
pela especificação (ufw delete ...), em qualquer posição:
- o bloqueio total do
block-ip(deny from <IP>); - desde a v2.60.0, também as regras de porta do
deny --port P --from <IP>(deny from <IP> to any port P [proto Y]). Antes, nenhum comando as removia.
As regras vêm do ufw show added (vale com o UFW inativo; sem ele, do
ufw status numbered) e casam pelo endereço, não pelo texto: IPv6 em
qualquer grafia casa, e 203.0.113.90 não casa com 203.0.113.9. Regra de
destino específico, de saída ou allow não é tocada.
Desde a v2.60.0 a resposta é honesta quando não há o que remover: sem regra
nenhuma para o IP, avisa "nada a remover" e sai 0 com removed: false
(como o unban de alvo não banido). Até a v2.59.0 dizia "IP desbloqueado"
sem remover nada, porque o ufw delete de regra inexistente sai 0. Falha real
do ufw continua saindo com erro.
JSON firewall.unblock-ip: ip, removed, rules (especificações
removidas; em --dry-run, as que sairiam) e dry_run. O
`implant unban` enxerga e remove as mesmas regras.
sudo implant firewall deny --port 22 --from 203.0.113.9
sudo implant firewall block-ip 203.0.113.9
sudo implant --dry-run firewall unblock-ip 203.0.113.9 # lista as duas regras
sudo implant firewall unblock-ip 203.0.113.9 # remove as duas
sudo implant firewall unblock-ip 203.0.113.9 # "nada a remover", exit 0
`rate-limit --port [--proto tcp|udp]`
Aplica ufw limit (6 conexões em 30s) — útil para SSH em porta custom.
Para rate-limit por origem com connlimit/hashlimit, veja
rate-limit.
`status`
Estado consolidado do firewall: ativo/inativo, defaults e regras.
`enable` / `disable`
Habilita/desabilita o ufw (ufw --force enable / ufw --force disable).
O enable não pede confirmação: garanta antes que a porta SSH está
liberada (implant firewall allow --port <porta-ssh>).
`audit [--strict]`
Auditoria somente leitura do firewall (v2.60.0+): não muda nada no host. Responde se o firewall está fechado de fato, o que há de cru fora do implant e se tudo volta no boot.
sudo implant firewall audit # relatório
sudo implant firewall audit --strict # exit 1 se houver achado crit
sudo implant -o json firewall audit # envelope firewall.auditCada achado tem id, severity (ok, warn ou crit), title, detail
e fix (o comando sugerido, quando há um). <família> é ipv4 ou ipv6.
| id | O que olha | Severidade |
|---|---|---|
policy.input.<família> |
Policy da INPUT. Fechada = policy DROP, DROP/REJECT incondicional no fim, ou UFW ativo com default deny/reject (incoming) |
crit se aberta; warn se aberta mas com ganchos do implant (blocklist, geo-block, rate-limit); ok em v6 sem endereço IPv6 global |
policy.forward.<família> |
Policy da FORWARD | warn se aberta com encaminhamento ligado; ok com encaminhamento desligado |
docker_user.<família> |
Blocklist do implant na DOCKER-USER (só com Docker) | crit se está na INPUT e não na DOCKER-USER (IP banido alcança containers); warn com UFW ativo e nada na DOCKER-USER |
ufw.order.<família> |
Ganchos do implant antes do primeiro salto para o UFW | crit se blocklist/geo-block estão depois (o ALLOW do UFW passa antes) |
ufw.raw_rules.<família> |
Com UFW ativo: regra direta na INPUT/FORWARD/OUTPUT fora das chains do UFW, do implant, do fail2ban e do Docker | warn |
orphan.<família>.<chain>.<posição> |
DROP/REJECT de IP/CIDR solto na INPUT/DOCKER-USER, fora do ipset do implant | warn, com fix: implant ban <ip> --permanent; faixa reservada (anti-spoofing) só informa |
log.unlimited |
-j LOG sem limite (mesmo detector do iptables audit-log-rules) |
warn |
persistence.rules |
Regras do implant, DROP cru e policy DROP própria voltam no boot (netfilter-persistent + iptables-persistent, serviço habilitado, ganchos no rules.v4/rules.v6; ou, sem ele, a reaplicação pela unit implant-firewall-restore, v2.61.0+, que só traz as regras do implant) |
crit se ganchos ou policy DROP somem no reboot; warn se só DROP cru ou policy própria somem (reaplicação) |
persistence.ipsets |
Sets IMPLANT_* em uso: unit implant-firewall-restore ativa e sets no arquivo |
crit se voltam vazios |
Exemplos de fix: implant ban 203.0.113.7 --permanent,
implant rate-limit reconcile, implant iptables audit-log-rules --fix. Com
o UFW instalado, o audit não sugere iptables-persistent: os dois pacotes
conflitam no apt.
Exit code: 0 sempre (é auditoria). Com --strict, sai 1 se houver algum
achado crit — útil em automação.
JSON (--output json, Envelope 1.0), comando firewall.audit:
{
"overall": "crit",
"counts": { "ok": 5, "warn": 3, "crit": 1 },
"strict": false,
"ufw_active": false,
"families_scanned": ["ipv4", "ipv6"],
"findings": [
{ "id": "orphan.ipv4.INPUT.4", "severity": "warn",
"title": "DROP solto de 203.0.113.7 na INPUT (ipv4)",
"detail": "regra crua ... iptables -D INPUT -s 203.0.113.7/32 -j DROP",
"fix": "implant ban 203.0.113.7 --permanent" }
],
"notes": []
}Família sem iptables-save/ip6tables-save vira nota em notes e fica de
fora de families_scanned.
Simular (`--dry-run`)
Desde a v2.59.0, allow, deny, block-ip, unblock-ip, rate-limit,
enable e disable respeitam o --dry-run global: mostram o que fariam sem
chamar o ufw. Até a v2.58.0 o flag era ignorado e a mudança era aplicada.
sudo implant --dry-run firewall block-ip 203.0.113.50Saída JSON
Com --output json, mutações retornam envelopes por ação
(firewall.allow, firewall.enable, …) e status retorna o estado do
UFW.
Exemplos
# Liberar HTTPS
sudo implant firewall allow --port 443
# Liberar PostgreSQL só para a rede interna
sudo implant firewall allow --port 5432 --from 10.8.0.0/24
# Bloquear um IP (v4 ou v6) — entra no topo das regras
sudo implant firewall block-ip 203.0.113.50
sudo implant firewall block-ip 2001:db8::50
# Fechar o SSH para uma faixa
sudo implant firewall deny --port 22 --from 198.51.100.0/24
# Estado em JSON
implant --output json firewall status
# Auditar o firewall (exit 1 se houver achado crit)
sudo implant firewall audit --strictVeja também
- ban / unban — ban no ipset central;
unbantambém remove as regras do UFW - iptables — alternativa low-level com anti-tijolar
- fail2ban — bans dinâmicos baseados em padrões