Changelog
[2.65.1] - 2026-10-21
Corrigido
--for-containernao desempatava quando dois Traefik veem o mesmo app (os dois com o provider do Docker e os mesmos rotulos): devolviatraefik_ambiguoussempre. Agora desempata pelo alcance de rede: primeiro o Traefik numa rede do Docker em comum com o app, depois o da rede do host; um Traefik que nao alcanca o app nao conta. Continuatraefik_ambiguousso no empate real.
[2.65.0] - 2026-10-21
Adicionado
- Escolha do Traefik por comando:
--traefik <container>e--for-container <app>emtraefik-accesslog,traefik-ratelimitetraefik-edge. O--for-containeracha o Traefik que roteia para o app pela API de cada Traefik. - Mais de um Traefik e nenhuma indicacao: recusa com
failure.code = traefik_ambiguouse uma sugestao por instancia, em vez de escolher. Indicacao que nao resolve:traefik_not_found,container_not_routedoucontainer_not_found. Com um Traefik so, nada muda. - Traefik configurado so por argumentos: o throttle L7 funciona (file-provider e API lidos dos argumentos), e as falhas trazem as flags a acrescentar. No
traefik-accesslogo resultado continuamanual, com as flags exatas que faltam (add_cmd_args,add_cmd_args_stdout,add_cmd_args_file).
[2.64.1] - 2026-10-21
Corrigido
- Throttle aceitava o IP de uma sessao SSH ativa quando rodava fora dela (por um console ou agente, sem
$SSH_CONNECTION), e o IP do proprio servidor. A protecao considera todas as sessoes SSH ativas do host e os enderecos das interfaces.failure.code = ip_protectedganhareason_code:private_range,ssh_session_activeouown_server_ip.
[2.64.0] - 2026-10-21
Adicionado
- Access log em Traefik gerenciado por orquestrador, pelo proprio orquestrador: quando o
traefik.ymlvem de um template, otraefik-accesslog --enablepede ao orquestrador o redeploy com o access log ligado (e o filtro de status,400-599ouall) em vez de recusar. Confere que o deploy ficou pronto, cuida do logrotate e da permissao no diretorio montado e confere o arquivo de log. Se o novo Traefik falha, o orquestrador devolve o anterior; o JSON diz se houve volta (deployally_failed_rolled_back/deployally_failed_no_rollback) e o campodeployallytraz o comando e o resultado. - Alerta
traefik_redeploy_failed:warnquando o Traefik anterior voltou,critquando nao houve volta.
[2.63.0] - 2026-10-21
Adicionado
- Mitigação por IP com prazo, em duas camadas, para limitar uma origem de tráfego sem banir. Ver mitigations.
- L4 (firewall),
rate-limit throttle <ip> --tier light|strict --ttl: conexões TCP novas do IP, na INPUT e nas portas publicadas de container; o kernel expira o prazo, e os sets voltam no boot. - L7 (Traefik),
traefik-ratelimit throttle <ip> --router <r> --rate N/s --ttl: requisições do IP num router, com 429 acima da taxa, sem reiniciar o Traefik. Um router-sombra mantém o serviço, o tls e os middlewares do router original. mitigations listjunta as duas camadas num formato só;mitigations sweep(por timer) expira as L7.- JSON com
failure {code, reason, suggestions[]}.
- L4 (firewall),
- Auto-ban: os DROPs do throttle L4 contam com peso 1/3 no sinal
iptables_drops; o 429 do L7 não conta.
[2.62.0] - 2026-10-21
Adicionado
traefik-accesslog --enable --to stdout: liga o access log sem montar diretório, para Traefik criado pordocker runou por outra ferramenta (sem docker-compose). O bloco vai semfilePath, o Traefik só reinicia (não é recriado) e o Docker guarda o log no host (driverjson-file). Recusa sem gravar se o container usa outro driver de log; avisa se o log do container não temmax-size. JSON:destinationedocker_log.- Auto-ban lê o access log do stdout: o sinal
traefik_httpganhasource: auto|file|docker(padrãoauto: o arquivo, se existir; senão o log do Docker do container do Traefik) econtainer. Entende a linha no envelope do Docker e ignora o log próprio do Traefik. traefik-accesslog --enable --status <all|faixas>: o que o access log registra.alltira o filtro (inclui 2xx); faixas e códigos como200-299,400-599. Ao ligar, o padrão continua400-599; num bloco existente só muda quando passado. Filtro por caminho não existe no access log do Traefik: para isso, ligue o log só nos routers que interessam (observability.accessLogs, Traefik ≥ 3.1).- Motivo e saídas de toda falha: o JSON do
--enable/--disableganhafailurecomcodeestável,reasonesuggestions[](id,title,detail,command,available), para um console mostrar ao operador por que falhou e o que fazer. A saída humana mostra as mesmas sugestões. IMPLANT_TRAEFIK_CONTAINER: escolhe o container quando o host tem mais de um Traefik.
Alterado
- Traefik cuja config é gerada por um orquestrador (o
traefik.ymlvem de um template): o implant não edita mais esse arquivo, nem no--enablenem nofix --auto, porque o próximo deploy desfaria a mudança. Responde com o motivo e a sugestão de ligar o access log pelo próprio orquestrador. - Traefik que não volta depois do
--enable(instalação): otraefik.ymlvolta ao original e o Traefik é reiniciado com ele.
[2.61.2] - 2026-10-21
Corrigido
traefik-accesslog --enabledeixava a configuração pela metade em Traefik sem mount de log que não vem de docker-compose (orquestrador com manifesto proprio,docker run). Gravava o blocoaccessLognotraefik.yml, criava o logrotate e o/var/log/traefik, falhava ao montar o volume e terminava com "✓ Configuração do access log foi aplicada", sem reiniciar o Traefik: a mudança ficava pendente para o próximo restart, com o log indo para dentro do container (sem rotação, perdido a cada recriação). Agora a impossibilidade é conferida antes de qualquer gravação: nada é alterado, o comando sai 1 com o motivo e o JSON (inclusive o--dry-run) vemresult: failedcomerrors. Se o volume ou o restart falharem depois de gravar (caminho do compose), otraefik.ymlvolta ao original e o logrotate criado na execução é removido (restored_original).- Traefik criado por orquestrador com manifesto proprio aparecia como "Manual" no status. Agora e reconhecido pelo manifesto, e o implant nao acrescenta volume por fora dele (o mount de log tem de vir do proprio orquestrador). Saiu um caminho antigo que editava um manifesto de formato aposentado e reiniciava o container sem o volume.
Adicionado
--enableconfere o resultado depois do restart: o Traefik ficou de pé e o arquivo do access log existe no host. JSON:traefik_up,log_file,log_written; a saída humana diz as duas coisas em vez do "habilitado com sucesso" incondicional.
[2.61.1] - 2026-10-18
Adicionado
traefik-accesslog --enable|--disable --yes(-y): aplica sem perguntar, para task sem TTY (console de gerenciamento, que mostra o plano do--dry-rune confirma na própria tela). Sem a flag, sem TTY a confirmação continua recusada e nada muda.--yescom--fix-permsé recusado (ele nunca pergunta). Implant anterior sai 2 (clap) com--yes.- JSON do
--enable/--disableem envelopes próprios,traefik-accesslog.enableetraefik-accesslog.disable(antestraefik-accesslog, que só repetia as flags), no--dry-rune no apply.data:dry_run,result(applied|unchanged|dry_run|cancelled|failed|manual|unsupported|not_found),mode(install: grava o bloco do implant;complete: completa o bloco do operador;remove:--disable),container,config_path,added[](key,value),replaced[](key,from,to: o que o--forcetroca),block(YAML doinstall),adds_log_volume,restart_planned,restarted,backup,restored_original(o Traefik não voltou e o original foi restaurado),traefik_up,logrotate(action:created|would_create|exists|covered|unavailable|failed|none;path,pattern,signal_container),perms(mesmo formato do--fix-perms),warnings[]eerrors[]. Falha:success: false,errorcom oserrorse exit 1. Com-o jsono stdout é só o envelope (o texto humano vai para o stderr). Com a query no plano do bloco (added), o aviso "grava a query" não se repete emwarnings. O status do access log continua nos itensAccess log do Traefik: …doimplant check -o json.
[2.61.0] - 2026-10-18
Adicionado
- `implant alerts`: alertas por Telegram ou webhook HTTPS, configurados pelo operador no próprio servidor. Canais nomeados em
[alerts.channels.<nome>](type = "telegram"comchat_id, outype = "webhook") e subscrições em[[alerts.notify]](on,channel,templatecom{{::hostname}},{{::event}},{{::target}},{{::severity}},{{::title}},{{::detail}},{{::ts}}) noconfig.toml. Credenciais (bot_token,url,authorization) só emalerts.secrets, ao lado doconfig.toml, 0600 root: arquivo com permissão aberta, de outro dono ou symlink não é lido; credencial posta noconfig.tomlé recusada. Subcomandosstatus,channel add telegram|webhook(token/URL por--token-stdin/--token-env,--url-stdin/--url-env,--auth-env; nunca por argumento;--replacepara rotacionar),channel remove,channel list(sem mostrar segredo),subscribe,unsubscribeetest --channel(mensagem de teste). Edição doconfig.tomlpreserva comentários;--dry-runem todos. - Eventos:
ban_permanent(auto-ban aplicou ban permanente),threat_crit(seção dothreat-statusentrou emcrit, quando o snapshot é gravado),lockdown_created(lockdown create,ssh-service disable),emergency_mode_enabled,firewall_boot_fallbackefirewall_install_reverted(firewall-restore sem confirmação),feed_kept_previousefeed_refused(feed-block falhando). - Entrega best-effort: prazo por envio (
timeout_seconds, padrão 5 s) e no máximo 20 s por chamada, sem retry; falha vira registro em/var/lib/implant/alerts-events.jsonle nunca falha o comando ou o daemon que gerou o evento. Dedupe por evento + alvo (dedupe_window_seconds, padrão 1 h) e teto por hora (max_per_hour, padrão 20). Só HTTPS, sem seguir redirect; mensagens de erro passam por filtro que tira valores de credencial. - As regras do implant voltam no boot sem o
netfilter-persistent. Instalar o UFW removeiptables-persistent/netfilter-persistentno apt, e até aqui só os ipsets voltavam no reboot. A unitimplant-firewall-restore, depois doipset restore, passa a rodarimplant firewall-restore boot-rules, que reaplica a partir dos states: o rate-limit pelo mesmo caminho dorate-limit reconcile, e os ganchos do feed-block e do geo-block sobre os sets restaurados. Com o netfilter-persistent carregando orules.v4(ferramenta, plugin, serviço habilitado e arquivo), nada é reaplicado: uma fonte só. Rate-limit suspenso (revert --keep-state, emergency-mode) não volta; geo-block em allowlist sem o set restaurado fica sem gancho para não trancar o host. - Ordem com o UFW: a unit roda
After=ufw.service(comMANAGE_BUILTINS=yesoufw-initesvazia a tabela filter inteira) e os ganchos entram na posição calculada, acima das chains do UFW nas duas ordens de subida. Com o Docker instalado, aDOCKER-USERé criada antes dele para os ganchos entrarem nela. - Fail-open: erro num componente não para os outros nem o boot (
ExecStart=-, teto de 120 s, o comando sai 0). O resultado fica em/var/lib/implant/firewall-restore/boot-rules.jsone, em falha, vira o eventoboot_rules_failedna guarda do firewall-restore. A guarda de boot é armada depois da reaplicação; o fallback dela esvazia os sets de bloqueio que esses ganchos leem. firewall-restore statusganharules_mechanism(netfilter-persistent|implant-firewall-restore|null),boot_rules(último resultado) eboot_rules_failed. O check "Boot-survival do firewall", oban/ban test(persisted) e ofirewall audit(persistence.rules) aceitam a reaplicação como mecanismo; o check reprova se a reaplicação deste boot falhou, e o audit avisa que DROP cru e policy DROP própria não voltam por ela.- A unit muda (
up_to_date: falsenos hosts com a da 2.51–2.60). Oself-updatea troca pelo caminho de sempre:firewall-restore ensure→rate-limit reconcile, com a guarda.
Corrigido
checkreprovava Boot-survival até o próximo boot mesmo com as regras já refeitas. Depois de um boot em que a reaplicação falhou (fail-open), orate-limit reconcile(oufeed-block apply,geo-block apply) refazia as regras, mas o check seguia apontando a falha do boot. Agora o passo daquele componente virarecoverednoboot-rules.jsone só o que continua falho reprova.- Alerta que falhava ao enviar entrava no dedupe. Um envio que estourava o prazo contava na janela e no teto por hora, e a repetição do mesmo evento saía como
duplicate: o alerta se perdia pela janela inteira (1 h por padrão). Agora só o envio entregue a pelo menos um canal conta. - O arquivo de boot não grava mais as regras do Docker. O save do implant (rate-limit, feed-block, isenção da VPN no rate-limit e
implant iptables save) eranetfilter-persistent save, que levava oiptables-saveinteiro: container ou rede removidos depois ficavam norules.v4e voltavam a cada boot (DNAT para IP de container que não existe mais, MASQUERADE de rede apagada, DOCKER-ISOLATION-*). Agora o implant gravarules.v4|v6sem as chainsDOCKER/DOCKER-*, sem os saltos para elas e sem as regras do Docker na FORWARD, na POSTROUTING (nat) e na PREROUTING (raw). ADOCKER-USER(onde moram os ganchos do implant) e o salto da FORWARD para ela ficam, assim como tudo do operador. Dump sem a tabela filter nunca vira arquivo vazio. Provado comiptables-savereais (Docker ≤ 27 e 28/29). traefik-accesslog --enablenão acrescentavaaddInternalsa um access log que já existia. Respondia "Access log já está configurado" e não mudava nada; desde a 2.51 a chave só entrava quando o log era ligado do zero. Sem ela o Traefik 3 não registra o 403 da guarda dotraefik-edge(noop@internal) e o sinaltraefik_httpdo auto-ban não vê o scanner. Agora, com Traefik ≥ 3 e blocoaccessLogsem a chave, o--enableacrescentaaddInternals: trueao bloco do operador (edição por linha, conferida pelo parser: comentários, ordem e os demais campos ficam), mostra o plano no--dry-run, faz backup e reinicia o Traefik conferindo que ele voltou (se não voltar, restaura o original). Quando o Traefik aceita o corte da query, ele vai na mesma gravação: um restart só. Traefik 2 nunca recebe a chave; versão não identificada: não grava e avisa;addInternals: falseescrito pelo operador só muda com o novo--force. Config por linha de comando ou TOML: o implant aponta a flag/chave a acrescentar. Ocheckganha o itemAccess log do Traefik: addInternals(Fail com o comandoimplant traefik-accesslog --enable) e o status dotraefik-accesslogmostra a linhaaddInternals.- A rotação do access log mandava o USR1 para o container errado. O logrotate instalado (
/etc/logrotate.d/traefik) tinhadocker kill --signal=USR1 traefikcom o nome fixo; em host cujo container se chama outro (ex.proxy) o Traefik não reabria o arquivo, seguia escrevendo no rotacionado, oaccess.lognovo ficava vazio (o auto-ban deixava de ver) e a rotação seguinte comprimia o arquivo em uso. Agora o logrotate nasce com o nome do container detectado, e um logrotate existente com outro nome é corrigido pelo--enable,--fix-permsefix --auto(backup, só o nome muda, sem restart do Traefik), como já acontecia com ocreate 0644. Ocheckganha o itemAccess log do Traefik: rotação(logrotate ausente ou USR1 para outro container); o status aponta o nome errado. JSON do--fix-perms:logrotate.signal_before,signal_after,signal_expected. - Access log em volume nomeado do Docker ficava sem rotação. O logrotate do implant só cobria
/var/log/traefik/*.logdo host; quando o/var/log/traefikdo container é um volume nomeado (/var/lib/docker/volumes/<nome>/_data), o log crescia sem limite e com o modo antigo. Agora o caminho no host vem dos mounts do container (docker inspect, bind ou volume nomeado, o mount mais específico que cobre ofilePath): o logrotate novo nasce para esse diretório, o existente com o padrão antigo/var/log/traefik/*.logpassa a apontar para ele (padrão escrito pelo operador não é tocado), e o ajuste de permissão 0640 vale para lá. O--enablecom o access log já ligado instala o logrotate que faltar (se nenhum outro arquivo de/etc/logrotate.djá cobrir o diretório). Log sem mount no host (só dentro do container) e log no stdout aparecem no status e no itemAccess log do Traefik: rotaçãodocheck; o status mostra o arquivo no host e avisa quando o auto-ban lê outro caminho. JSON do--fix-perms:location,logrotate.patterns_before,patterns_after,covers_dir;dir.pathpassa a ser o diretório real. - Access log em texto passava despercebido. O leitor do sinal
traefik_httpdo auto-ban só entende JSON (linha que não é JSON é descartada), e um blocoaccessLogsemformatgravacommon(texto): o auto-ban não via nenhuma linha. O--enableem bloco existente semformatacrescentaformat: json(mesma edição, plano, dry-run, backup e restart doaddInternals, numa gravação só);formatexplícito diferente (common,genericCLF) não é trocado sem--force— o--enableavisa. Ocheckganha o itemAccess log do Traefik: formatoe o status a linhaFormato; config por linha de comando ou TOML recebe a flag/chave a acrescentar.
[2.60.2] - 2026-10-17
Corrigido
--dry-rundepois do subcomando passa a valer emiptables,fail2ban,sysctl,harden-network,swap,limits,logrotate,docker-limits,lockdown,ssh-service,emergency-mode,rate-limiteban. Antes, algo comorate-limit unwhitelist-ip --ip X --dry-rundava "unexpected argument"; agora o--dry-runvale em qualquer posição, como no resto do CLI.self-update: o campochanneldo JSON vem da URL do download (rcpara o canal de release candidates); antes dizia semprestable.
[2.60.1] - 2026-10-17
Corrigido
rate-limit unwhitelist-ipdizia "IP removido" e o IP continuava isento. Agora tira o IP do set do kernel e do arquivo de sets do boot, e é idempotente. IP que também vem de outra fonte de whitelist continua isento, e a saída diz de onde vem.unbaneban testdivergiam quando o IP estava no feed externo. Os dois passam a usar o mesmo cálculo (still_blocked_by/blocked_by).ban testnão contava o UFW: umdenyque vem antes dosallowagora conta como bloqueio; atrás de um allow, o motivo aparece emwarnings.feed-blockcom-o jsonpassa a emitir o envelope de erro quando falha.
[2.60.0] - 2026-10-17
Adicionado
implant firewall audit(somente leitura): policy da INPUT/FORWARD em v4 e v6, blocklist do implant ausente da DOCKER-USER, ordem dos ganchos do implant em relação ao UFW, regras diretas fora das chains conhecidas, DROP/REJECT de IP solto fora do ipset, LOG sem limite e persistência no boot de regras e ipsets. Achados{id, severity: ok|warn|crit, title, detail, fix}; JSONfirewall.audit. Exit 0 sempre;--strictsai 1 se houvercrit.implant feed-block(opt-in): feed externo de blocklist (padrão Spamhaus DROP v4 e v6) nos ipsetsIMPLANT_FEED_BLOCK[6], julgados na INPUT e na DOCKER-USER, com timer semanal. Precedência dos ganchos passa a ser whitelist > blocklist > feed-block > geo-block > rate-limit. Feed ruim é recusado inteiro e o conteúdo anterior fica; troca poripset swap; anti-tranca filtra a sessão SSH, a whitelist e faixas privadas; intervalo mínimo de 1 h entre downloads sem--force.ban testmostrafeed/feed_entry/feed_enforced;unbannão tira do feed e indica a whitelist;threat-statusganha os DROPs do feed.implant traefik-ratelimit(opt-in): middleware de rate-limit L7 por IP no file-provider do Traefik (implant-ratelimit@file, opcionalinFlightReq). Não mexe em router: o operador anexa o middleware. Orevertrecusa se algum router o usa;revert --neutralmantém o nome sem limite.- emergency-mode: features
feed-blocketraefik-ratelimit. O feed-block sai porreverte volta porapply; o traefik-ratelimit sai porrevert --neutral(nunca remove middleware em uso) e volta porapplysem flags.
Corrigido
firewall unblock-ipdizia "IP desbloqueado" sem remover nada. Oufw deletede regra inexistente sai com exit 0 e só avisa "Could not delete non-existent rule". Agora isso conta como "não havia regra": aviso "nada a remover", exit 0 (como ounbande alvo não banido) eremoved: falseno JSON. O JSONfirewall.unblock-ipganharemoved,rules(especificações removidas; em dry-run, as que sairiam) edry_run. Falha real do ufw continua saindo com erro.- Nenhum comando removia o
firewall deny --port P --from X. Ounblock-ip Xpassa a remover também as regrasdeny from X to any port P [proto Y], casadas pelo endereço (IPv6 em qualquer grafia;203.0.113.90não casa com203.0.113.9). Regras de destino específico, de saída eallowficam. Oimplant unban Xenxerga e remove as mesmas regras (antes respondia "não estava banido"). ban testnão dizia se o bloqueio sobrevive a reboot. Agora diz, com o mesmo cálculo doban: linha "sobrevive a reboot: sim/NÃO" e campopersistedno JSONban.test(nullquando o alvo não está na blocklist), com o motivo emwarningsquando não sobrevive.
Documentação
- Páginas novas: feed-block e traefik-ratelimit.
- firewall documenta o
firewall audit. ban,emergency-mode,rate-limitegeo-blockatualizados com o feed-block na precedência (whitelist > blocklist > feed-block > geo-block > rate-limit) e as novas features do emergency-mode.- Os comandos
feed-block,traefik-ratelimitefirewall auditchegaram na v2.59.0; as entradas correspondentes foram acrescentadas abaixo.
[2.59.0] - 2026-10-17
Adicionado
self-updateleva a unitimplant-firewall-restorepara o servidor. Depois de trocar o binário, executa o binário novo comfirewall-restore ensure, com teto de 300 s. Falha nesse passo nunca faz o self-update falhar: vira aviso e o campopost_updatedo JSON (status:ok,failed,plannedoudisabled). Opt-out:--no-post-updateouIMPLANT_NO_POST_UPDATE=1. Vale a partir do update feito por esta versão: quem atualiza a partir da 2.58.0 ou anterior só o ganha no update seguinte (ou comfirewall-restore ensureà mão).implant firewall-restore ensure: roda orate-limit reconcilesó quando ele instalaria a unit; senão não faz nada (o rate-limit não é reaplicado a cada atualização). Idempotente, seguro à mão e respeita--dry-run. Novosboot_unit_action:suspendedeunsupported_schema.- fail2ban:
use-ipset-action --enable/--disable(opt-in). Os bans das jails do implant vão direto para a blocklist central, que vale para o host e para os containers, sem chainsf2b-*paralelas. Cria só dois arquivos com a marca do implant, valida comfail2ban-client -te desfaz se reprovado;--disablevolta exatamente à action anterior. Timeout =bantime(permanente vira entrada sem timeout); whitelist e bans de outra origem têm precedência.fail2ban statusganhaipset_action. - emergency-mode: feature
fail2ban-ipset, desligada antes dorate-limit: durante a emergência o fail2ban volta à action própria e o SSH continua protegido. implant reset --fail2bantambém apaga os arquivos da action do implant.- Documentada a divisão de papéis: detecção HTTP no auto-ban
(
traefik_http), fail2ban para o SSH.
Corrigido
geo-block apply --dry-runaplicava de verdade. Agoraapply,update,revert,add-countryeremove-countrysimulam sem gravar nem aplicar nada (oapplyainda roda a checagem anti-tranca).firewall allow/deny/block-ip/unblock-ip/rate-limit/enable/disabletambém passam a respeitar o--dry-run, eauto-ban scanpassa a aceitá-lo. Subcomandos que mudam o host e não sabem simular recusam o--dry-runem vez de executar:geo-block service install/uninstall/start/stop,auto-ban allow/unallow/offenses-clear/service,firewall-restore(excetostatuseensure),capture prune/serviceeaudit apply/revert/service.- Allowlist do geo-block recusado pela anti-tranca ficava gravado e o
update do timer o aplicava depois, sem proteção. Agora o config só é gravado
depois da checagem, e o
updatesó repopula config já validado; o resto é recusado (update_refusednostatus). Ostatusmostravalidated_at/validated_by. firewall block-ipnão bloqueava as portas já liberadas. O DENY ia para o fim da lista, depois dosallow. Agora entra no topo da família do endereço (v4 e v6); vale também parafirewall deny --port P --from X.- Boot-survival aprovava sem as regras voltarem no boot. Instalar o UFW
remove
iptables-persistent/netfilter-persistentno apt. O check passa a exigir também a persistência das regras e reprova dizendo o que falta; obansó responde "sobrevive a reboot: sim" com sets e regras; o rate-limit avisa e responderules_persist_warningem vez de erro sem causa.
[2.58.0] - 2026-10-17
Alterado
rate-limit reconcileinstala sozinho a unitimplant-firewall-restore, com guarda. Se a unit falta, é a antiga (≤ 2.50.0, que não rodava no boot) ou está desabilitada, o reconcile instala comofirewall-restore install --confirm-timeout 10 --boot-guard. O agente de controle remoto confirma sozinho; sem confirmação, a guarda desfaz (fail-open). Instalação automática desfeita não é tentada de novo: o reconcile só aponta.rate-limit applyecheck --auto-fixcontinuam só apontando. JSON do reconcile ganhaboot_unit_action,boot_unit_planeboot_unit_install.
[2.57.0] - 2026-10-16
Adicionado
- wireguard: várias redes por servidor.
implant -o json wireguard networks(somente leitura) lista todas as redes do host — confs e interfaces no ar sem conf —, commanaged_bylido do cabeçalho do conf,role(hub/client), peers e estado do firewall. Nenhuma saída traz chave privada. - wireguard:
remove --iface X [--force]remove a rede inteira: para a unit, fecha a porta, tira a isenção do rate-limit, apaga o drop-in de boot e guarda o conf emX.conf.removed-<data>(600, nunca apaga). Rede inexistente dáabsent. Sem--force, recusa awg0e redes que o implant não criou. - wireguard / rate-limit: a porta UDP de cada rede fica isenta do
rate-limit, presa à rede (
wireguard-<iface>).initpõe,removetira,disablemantém. Blocklist e geo-block continuam valendo.
Corrigido
- wireguard: detecção do firewall única em
init,status,disableeremove. Num servidor com INPUT aberto, oinitreportavanonee odisableda mesma rede reportavaiptables.
[2.56.1] - 2026-10-16
Alterado
- traefik-edge: o
--helpdo--with-404e o audit descrevem o catch-all como ele é: pega só host sem router e responde 403; host com serviço segue com o 404 do próprio serviço. Comportamento inalterado.
[2.56.0] - 2026-10-16
Adicionado
- traefik-edge: lista de bloqueio própria. O operador acrescenta
caminhos completos e literais à guarda (mesmo 403, Traefik 2 e 3), em
[traefik_edge] bloqueardoconfig.tomlou por--configure --bloquear <entrada>/--desbloquear <entrada>. Barra inicial = a partir da raiz; sem barra inicial = em qualquer pasta; barra final = a pasta e tudo dentro. Sem curingas nem regex; entrada inválida dá erro e nada é gravado. O audit lista as entradas e testa uma delas.
Alterado
- config.toml parcial passa a carregar: seções ausentes caem no padrão (antes o arquivo precisava de todas as seções).
- traefik-edge: editar a lista não remove o catch-all de hosts sem router já instalado; o cabeçalho do arquivo de guarda não cita mais referência interna.
[2.55.1] - 2026-10-16
Corrigido
- docker-limits / check: o
daemon.jsonpassa pelodockerd --validateantes de ser gravado. Se o dockerd recusar o resultado (ex.: chave desconhecida, que o impede de subir), nada é gravado e o Docker não é reiniciado; a mensagem traz o motivo. Vale paradocker-limits apply/revert,reset --docker-limitse ocheck --auto-fix. Docker sem--validate(anterior ao 23) segue como antes, com aviso. - limits / docker-limits: status sem
✗depois dorevert. A ausência do bloco é o resultado esperado e não aparece mais como comando falho.
[2.55.0] - 2026-10-16
Corrigido
- docker-limits: o
daemon.jsondo usuário é preservado.applyerevert(ereset --docker-limits,check --auto-fix) fazem o merge semjqe mexem só nas chaves do implant (default-ulimits,live-restore,userland-proxy;log-driver/log-optssó quando não há log configurado). O valor anterior de cada chave fica em/var/lib/implant/docker-limits.json, e orevertdevolve cada uma a esse valor se ela ainda tem o valor do implant. JSON inválido dá erro sem tocar no arquivo, e o Docker só é reiniciado se o arquivo mudou. Antes, semjq, oapplysubstituía o arquivo, e oreverto apagava inteiro. - limits: o
revertnão apaga mais até o fim dolimits.conf. O bloco do implant ganhou marcador de fim (# Fim limites Implant) e orevert(ereset --limits) remove só o que está entre os marcadores. Em blocos antigos, sem o marcador de fim, remove só as linhas no formato que o implant grava. - logrotate:
applyrespeita o--dry-run(planoFaria:, campoplannedno JSON). O backup da config do rsyslog saiu de/etc/logrotate.d/rsyslog.backup.implant, que o logrotate lia como configuração (duplicate log entry), e foi para/var/lib/implant/backups/logrotate/; o backup antigo é migrado no próximoapply. - reconfigure:
--backupfaz backup de verdade (ligado por padrão) em/var/lib/implant/backups/reconfigure-<timestamp>/(0700):/etc/fstab,/etc/docker/daemon.json, config e units/env do K3s. Em dry-run, lista o que seria copiado.--no-backupdesliga; a saída JSON ganhabackup_dir. - agent: o token não aparece mais. O token e o corpo do registro chegam ao
curlpor variável de ambiente e o cabeçalho pelo stdin: ficam fora do--dry-run, do--verbose, das mensagens de erro e dops. O--dry-runnão para mais ao tentar ler o certificado, que só é gerado na instalação real. - self-update: comparação de versão exata. Antes era por substring, e a
troca entre estável e RC (
X.Y.Z-rc.N↔X.Y.Z) era recusada sem--force. - install node:
--versionperdeu o-v, que é o--verboseglobal. sysctl,limits,logrotateedocker-limitsnão listam mais os subcomandosemergency-*, que apareciam no--helpe só davam erro. Esses comandos não fazem parte doemergency-mode.--helprevisado: sem referências internas.
[2.54.0] - 2026-10-09
WireGuard
- A porta do firewall sobrevive ao reboot.
wireguard inite--adoptgravam o drop-in/etc/systemd/system/wg-quick@<if>.service.d/implant-firewall.conf(ExecStartPostque reabre a porta ao subir a interface). Antes, em host com política DROP e sem persistência de regras, a VPN subia no boot sem receber conexão. Odisablecontinua fechando a porta. - Novos
implant wireguard firewall open --iface <if>(idempotente, usa oListenPortdo conf, padrão 51820) efirewall status --iface <if>. - Corrigido:
init --adoptcom o drop-in já presente travava a unit emactivating (start-post). O drop-in ganhouTimeoutStartSec=90. - ufw: a regra
<porta>/udpsem comentário criada por versões anteriores à 2.53 é trocada pela regra marcada (wireguard-<if>), para que odisableconsiga fechá-la. O relatório indicafirewall_detail.migrated: true.
[2.53.0] - 2026-10-09
WireGuard
initabre a porta UDP no firewall (ufw, firewalld ou iptables com política DROP) edisablefecha.statusmostra o estado do firewall.- A saída de
init/disableganhafirewall_detail({kind, opened[, error]}); o campofirewall(string) continua igual.
[2.52.0] - 2026-10-09
Firewall-restore com confirmação e guarda de boot
implant firewall-restore install --confirm-timeout N(2–360 min): instala a unit sob um lockdown com dead-man — semimplant firewall-restore confirmdentro do prazo, a instalação é desfeita automaticamente.install --boot-guard [--boot-timeout N]: a cada boot cria um lockdown que, se não for confirmado, libera apenas as entradas de bloqueio do implant nos setsIMPLANT_*(whitelist, allowlist do auto-ban, regras e UFW ficam) e registra o que foi liberado por origem (ban,auto_ban,geo_block).- Novos subcomandos
confirm,arm --bootefallback;statusganhadata.guard.
Mudado
- A unit
implant-firewall-restoresó é instalada manualmente.rate-limit apply/reconcileecheck --auto-fixnão a instalam mais: o check reprova e aponta o install com guarda;applyereconciledevolvemboot_restore_advice.
[2.51.0] - 2026-10-09
Corrigido
- A unit
implant-firewall-restorenão rodava no boot (2.25.0–2.50.0): a ordenação gerava um ciclo e o systemd descartava o job. Após reboot os sets ficavam vazios e o host subia sem blocklist nem rate-limit, enquanto o check "Boot-survival" dava Pass.firewall-restore statusganhaup_to_date; o check reprova a unit antiga;banrespondepersisted: falsecom ela. iptables restoreagora substitui os ipsets pelo conteúdo do snapshot (ipset swap) em vez de mesclar — um ban posterior ao snapshot não sobra.iptables restorelogo após um snapshot (mesmo segundo) não restaurava nada; restaurar o 10º snapshot o apagava no prune.- auto-ban
traefik_httpcom config legada (traefik_404:): path de scanner respondido com 403 não pontuava. Campo novoscanner_statuses. traefik-accesslog --enableno Traefik 3 gravaaccessLog.addInternals: true, necessário para logar o 403 da guarda dotraefik-edge.
Adicionado
implant iptables restore --snapshot-id <N|timestamp>(1 = mais recente) eimplant iptables snapshots.
Atenção no upgrade
- Hosts com a unit antiga seguem sem restore no boot até rodar
implant firewall-restore install(ourate-limit reconcile/check --auto-fix). - Com a config legada do auto-ban, scanner que recebe 403 em path de scanner passa a ser banido (4 hits em 5 min).
[2.50.0] - 2026-10-08
Traefik: access log sem credenciais
- O access log gravava a query string completa (
?token=…). Com Traefik ≥ 3.6.18 / 3.7.2 o implant configuraaccessLog.fields.queryParameters.defaultMode: drop(o path continua no log). Versões anteriores não aceitam a chave: o check relata Fail pedindo a atualização do Traefik. - Novo módulo do check "Access log do Traefik" (
--modules traefik): permissão dos arquivos/logrotate e query string.implant fix --autorestringe a permissão e, quando o Traefik aceita, grava a chave (com backup), reinicia e confere que subiu — senão restaura o original. - Detecção do Traefik: imagens com tag (
traefik:v3.7.5) e containers identificados só por label não eram encontrados.
[2.49.0] - 2026-10-08
implant self-updatetambém recupera o agente de controle remoto quando ele está preso numa versão que não consegue se atualizar sozinha (binário conferido por SHA e assinatura minisign, com backup e restart agendado). Ocheckpassa a relatar esse caso.- wireguard: instala
iproute2junto comwireguard-tools(owg-quickfalhava em imagens mínimas).
[2.48.0] - 2026-10-07
Novo: `implant wireguard`
status,init [--adopt],peer add|remove|list,disable: instala e opera a VPN WireGuard do servidor e cadastra devices, devolvendo.confe QR (SVG no JSON, ANSI no terminal). A chave privada do device só aparece na saída dopeer add.initcom outro--endpointsó atualiza o endpoint (outcome: updated), sem reiniciar a VPN.--forcerecria a chave do servidor e remove todos os devices.--portnão combina com--adopt.
[2.47.1] - 2026-10-07
Consolida v2.47.0 → v2.47.1.
`ssh-key --whitelist-ip`
- Host sem UFW (ou inativo) não mostra mais "✗ Verificando UFW (falhou)": o passo aparece como pulado (⊘).
- O resumo lista só os alvos em que o IP ficou de fato isento (fail2ban, UFW, PerSourcePenalties, rate-limit do implant).
- Fail2ban só conta como isento quando o IP é item inteiro de
ignoreip(antes203.0.113.4casava com203.0.113.45). - OpenSSH < 9.8:
PerSourcePenaltyExemptListé pulado (a diretiva não existe) em vez de quebrar osshd_config.
[2.46.0] - 2026-10-06
Alterado
- Precedência das regras do implant passa a ser WL > BL > GEO > RL: IP
isento (whitelist/allowlist) vale acima da blocklist, na INPUT e na
DOCKER-USER, v4 e v6. Instalações antigas são corrigidas no próximo
rate-limit apply/reconcileoussh-key --whitelist-ip.
Corrigido
ssh-key --whitelist-ip: falha em qualquer passo aparece no resumo ("Whitelist FALHOU para N de M IP(s)") e o comando sai com código ≠ 0.ban test: IP na blocklist e na whitelist não aparece mais comoblocked.
[2.45.0] - 2026-10-02
- Novo
implant traefik-accesslog --fix-perms [--dry-run]: corrige só a permissão do access log (logrotatecreate 0640 root adm, arquivos 0640), sem prompt e sem reiniciar o Traefik. Nada que já esteja mais restrito é afrouxado. traefik-accesslog --enablecom o log já ligado agora também corrige as permissões.--dry-rundotraefik-accesslogexecuta as leituras de descoberta de verdade (antes concluía errado).
[2.44.1] - 2026-09-30
Corrigido
implant checksem--auto-fixescrevia no host (o módulo de apps baixava e tentava substituir binários). Agora o check sem--auto-fixé estritamente leitura em todos os módulos; o de apps compara a versão instalada com a publicada.--install-nodesem--auto-fixé ignorado com aviso.- Vários checks davam Fail em host correto por procurar a marca do implant em vez do valor efetivo (limites de log do Docker, limits.conf, sysctl, SSH Hardening, Logrotate, Journald, Fail2Ban). Todos passam a medir o valor efetivo.
- SSH Permissões:
/rootem2755é válido; a correção virouchmod go-w. - O Fail2Ban não sobrescreve mais um
jail.localque não seja do implant: grava/etc/fail2ban/jail.d/implant.conf.
Adicionado
- Itens SSH PasswordAuthentication e SSH PermitRootLogin (
yes= Fail de risco alto; só reportam). - Campo
risk(high|medium|low) nos itens do check.
Atenção no upgrade
- O resultado do check muda: hosts corretos deixam de acumular Fail falso, e
hosts com senha no SSH,
PermitRootLogin yesou Docker sem rate-limit ganham Fail novo.
[2.44.0] - 2026-09-29
implant ban <ip|cidr>(--ttl 24h,--permanent,--reason,--force,--fail2ban,--dry-run),implant unban,ban listeban test <ip>. A resposta informa onde o bloqueio está de fato ativo (enforced,effective). Guardas contra banir o próprio IP da sessão SSH, faixas privadas, loopback e whitelist; prefixos mais amplos que /16 (v4) ou /48 (v6) exigem--force.unbandesfaz no ipset, no fail2ban e no UFW, e encerra o cooldown do auto-ban.
[2.43.0] - 2026-09-28
Adicionado
- Chain
IMPLANT_RL_DROPcom LOG opcional e limitado por origem:implant rate-limit drop-log enable|disable|status. rate-limit add --docker <porta>/remove --docker <porta>: rate-limit de porta publicada pelo Docker (via DOCKER-USER).
Corrigido
- Sinal
log_authdo auto-ban não funcionava em syslog RFC3339 (Ubuntu 25.04, Debian recentes). Agora lê RFC3339 eshort-isodo journalctl; o formato antigo passa a ser interpretado em hora local. Semkern.log, o sinaliptables_dropslê do journal. harden-networknão grava maisvm.overcommit_memory = 2: em hosts acima doCommitLimitresultante todoforkfalhava, inclusive o SSH. O pack agora grava0, desfazendo o valor antigo no próximo apply.traefik-edge: a guarda passa a bloquear também arquivos de credencial (.credentials,.test_credentials,.htpasswd,.pgpass,.netrc, chaves SSH privadas sem extensão) em qualquer diretório. Aplicar comimplant traefik-edge --configure.
Atenção no upgrade
- O auto-ban volta a banir por
log_auth(10+ falhas de senha em 5 min). - O LOG do drop-log é opt-in; a chain nova entra no próximo
rate-limit apply/reconcile/add.
[2.42.0] - 2026-09-27
Corrigido
- Ordem das regras do implant passa a ser calculada (não mais em posição fixa) e igual na INPUT e na DOCKER-USER, independente da ordem de aplicação.
- Geo-block na INPUT podia não entrar, sem aviso. Agora usa a chain
IMPLANT_GEO_INe falha de instalação aborta oapply. - Emergency-mode perdia regras de
rate-limit adde a whitelist extra ao restaurar. - Unban manual deixava o IP imune ao auto-ban até o TTL vencer.
- O daemon do auto-ban passa a reiniciar sozinho quando o binário é atualizado.
Adicionado
implant rate-limit reconcile(reaplica a partir do state) erate-limit revert --keep-state.- Item Cobertura DOCKER-USER no
implant check. implant iptables audit-log-rules [--fix] [--restore]: encontra e remove regras-j LOGsem limite.geo-block applyem allowlist recusa se o IP da sessão SSH ficaria bloqueado, e tira snapshot antes de mexer.- Snapshots do
implant iptablesincluem IPv6.
Atenção no upgrade
- Hosts com rate-limit aplicado antes da 2.40.0 precisam de
implant rate-limit reconcile. - Neste upgrade, onde o auto-ban está ativo, rode uma vez
systemctl restart protocolo-implant-auto-ban.
[2.41.1] - 2026-09-25
Consolida v2.41.0 → v2.41.1.
- auto-ban: novo sinal
traefik_http(sucessor detraefik_404) pontua respostas 4xx com peso maior para paths de scanner (/.env,/.git,/wp-login.php…). A configtraefik_404antiga continua aceita. - auto-ban: um ban ainda vigente não conta mais como ofensa nova a cada ciclo (antes um único ban do fail2ban podia virar permanente).
- Segurança: access log do Traefik com permissão 0640 (antes 0644);
traefik-accesslog --enablecorrige arquivos e logrotate existentes. O status mostra a permissão e conta, sem ler valores, requisições com credencial na query.
[2.40.0] - 2026-09-06
Adicionado
- Seção
[endpoints]noconfig.toml(CDN, guardrail e catálogo de apps configuráveis) e[[tls_pins]]para pins SPKI próprios. Hosts sem pin usam validação WebPKI padrão. - Licença Apache-2.0.
Segurança
- Assinatura minisign obrigatória para hosts sem pin embutido (em
self-updatee na instalação de apps). Nos domínios oficiais nada muda. - Guardrail recusa URL com esquema diferente de
https.
Notas
- Sem
config.toml, o comportamento é idêntico ao anterior. ssh-key --add-public-key-urlpassa a funcionar com hosts de terceiros (HTTPS obrigatório).
[2.39.1] - 2026-09-04
Consolida v2.30.0 → v2.39.1, série de correções do traefik-edge:
- Descoberta do file-provider a partir do Traefik em execução (não do
primeiro
traefik.ymldo host), em qualquer via que o Traefik aceita (arquivo YAML/TOML com qualquer indentação, flags, variáveis de ambiente), respeitando a regra do próprio Traefik de usar uma única fonte (arquivo > flags > env). filename:(arquivo único) é reportado como riscofile_provider_single_filee o--configureexplica as alternativas.- Probe do efeito: o audit pede
/.git/HEADao próprio Traefik e reportaprobe_status; guarda presente sem 403 vira riscoguard_not_effective.recent_errorstraz as últimas linhas de erro relevantes do Traefik. implant traefik-edge --enable-file-provider [--apply]: liga o file-provider no compose do Traefik em duas etapas (dry-run com diff e plano;--applysó com plano recente e compose inalterado), com backup e rollback automático. Comtraefik.yml, o patch vai no arquivo; stacks do Portainer são encontradas.- Traefik 2.x anterior à 2.11 usa
ipWhiteListna guarda (ipAllowListno v3). --configurereinicia o Traefik quando o file-provider caiu na subida e prova de novo; flags--providers.file.*órfãs são removidas do compose.config_sourceno audit (file|flags|env).
[2.29.0] - 2026-09-03
- Novo
implant traefik-edge:--audit(padrão, só leitura) verifica se o Traefik corta paths sensíveis (.git,.env*,.secrets*, certificados,docker-compose*,Dockerfile*,*.log,.npmrc…) e devolverisk(sensitive_paths_unguarded|no_file_provider|ok).--configureescreve um arquivo de guarda no diretório do file-provider que responde 403 antes de qualquer serviço;--with-404opcional, idempotente, com backup e--dry-run. Sem restart quando o file-provider temwatch.
[2.28.1] - 2026-09-03
Consolida v2.28.0 → v2.28.1.
- Novo
implant audit ssh: trilha de conexões SSH (aceitas/falhas, origem, usuário, método, fingerprint) lida do journal do sshd, inclusivesshd-session(OpenSSH 9.x).--since(padrão "24 hours ago"),--limit;-o jsondevolve{total, accepted, failed, events[]}. - stdout limpo com
-o json(logs vão para stderr);self-updatehonra-o. - Chave pública minisign publicada no CDN.
install/update de subsistema não baixa mais em/tmp(tmpfs consome RAM): usa um temporário em/opt/<nome>/e troca o binário comrenameatômico.
[2.27.1] - 2026-08-21
Consolida v2.27.0 → v2.27.1.
- BBR + fq no hardening de kernel quando o kernel suporta (senão mantém
CUBIC). O implant confere o valor efetivo no kernel após aplicar;
implant sysctl statusreportarp_filter,congestion_controlerouting_role. ip_forwardpassa a considerar WireGuard (gateway VPN sem Docker recebiaip_forward=0). Hosts que roteiam usamrp_filter=2(loose).self-update --dry-runnão instala mais de verdade: verifica pin, download, assinatura e versão e para antes do backup.
[2.26.0] - 2026-08-08
Removido
- BREAKING —
--notifyremovido decheckefix. Scripts que usam a flag falham com "unexpected argument"; basta removê-la. A saída do implant é sempre local (stdout ou--output <FILE>); o envio de relatórios para um console remoto é responsabilidade do agente de controle remoto.
Alterado
- Nenhum IP confiável vem mais embutido no binário: use
security.trusted_ips(config.toml) /--whitelist-ip. O IP da sessão SSH atual continua sendo liberado por padrão.
[2.25.3] - 2026-07-22
Consolida v2.25.0 → v2.25.3.
- Ipsets sobrevivem ao reboot: nova unit
implant-firewall-restore.serviceeimplant firewall-restore install | uninstall | status. Snapshots doimplant iptablespassam a incluir os ipsets. Novo check "Boot-survival do firewall". (Ver correção da ordenação na 2.51.0.) ssh-key --add-public-keyaceita chaves com comentáriouser@host.- Servidor virgem: o módulo docker reconcilia
ip_forward=1na mesma rodada dofix; removido o falso "✗ Verificando ip_forward atual (falhou)".
[2.24.6] - 2026-05-23
Hotfixes consolidados v2.24.1 → v2.24.6 (4 bugs + 2 ajustes cosméticos encontrados após o release v2.24.0).
Capture
-Z rootem tcpdump — sem isso o daemon dropava privilégios pro usertcpdumpe não escrevia em/var/lib/implant/pcap/(owned by root).service installreportavaactive=truemas o daemon morria 1s depois.- Flag
--out PATHno extract (antes--output PATH, que colidia com o global--output FORMATcausando panic do clap parser). Quem tinha script: trocar--outputpor--out. - Inventory aceita
.pcap{N}— tcpdump com-Wadiciona sufixo de rotação (capture-YYYYMMDDHHMMSS.pcap0). Sem o fix,status/list/extractreportavam 0 arquivos mesmo com pcaps presentes. - Extract tolera daemon ativo — antes falhava com "truncated dump file"
quando o único candidato era o arquivo sendo escrito. Agora copia para
/tmp(snapshot) e aceita output ≥ 24 bytes (header pcap).
Audit
- Parser ignora
key=(null)literal que auditd emite quando evento não tem key. Antes poluíacounts_by_keyno threat-status com chave bogus. extract_fieldpara em 0x1d (Group Separator, usado em alguns formatos auditd) — evita gobble de campos adjacentes.
Geo-block
applylimpa hook do mode anterior —uninstall_hook(idempotente, ambas variações) é chamado antes deinstall_hook. Evita duplicata de regra no INPUT em mode switch, e o cenário "tijolar" (re-apply com ipset vazio em allowlist mode dropando tudo).
Compat
Quem está em v2.24.0–v2.24.5: atualize para v2.24.6. Não há mudança de config ou state file — só correções de comportamento.
[2.24.0] - 2026-05-23
Bundle release: implant capture + implant audit + geo-block allow-list mode.
implant capture (v2.24.0 feature 1/3)
Daemon tcpdump rotativo + extract query expressiva (combina time + IP + porta + proto). Output pcap + meta.json com port→process enrichment.
implant audit (v2.24.0 feature 2/3)
auditd STIG-light ruleset + events CLI + 9º collector no threat-status.
geo-block allow-list (v2.24.0 feature 3/3)
--mode allowlist complementa blocklist. State v2.0 backward-compat.
Emergency-mode
6 OPT_IN_FEATURES (harden-network + rate-limit + auto-ban + geo-block + capture + audit). emergency-disable desabilita tudo junto.
[2.23.0] - 2026-05-22
Geo-block — bloqueia tráfego INPUT por país via IPDeny + ipset. systemd-timer semanal para update. Whitelist (rate-limit + auto-ban) bypassa geo-block.
Added
implant geo-block service install/uninstall/start/stop/status/logsimplant geo-block apply [--countries CN,RU,KP]implant geo-block revert/updateimplant geo-block add-country/remove-country/list-countries/statusimplant geo-block config show/path
Refator
IMPLANT_RATELIMIT_WHITELIST chain agora ACCEPT (não RETURN) + match para IMPLANT_AB_ALLOW. Whitelist real-bypassa rate-limit + geo-block.
Topologia INPUT
[1] RL_BLOCKLIST DROP [2] WHITELIST ACCEPT [3] GEO_BLOCK DROP [4] RATELIMIT
Emergency-mode
geo-block é 4º opt-in. emergency-disable desabilita 4 features juntas.
[2.22.0] - 2026-05-22
Auto-ban — daemon systemd que lê fail2ban, log_auth, iptables_drops e Traefik 404 e banha IPs ofensivos via blocklist com TTL progressivo por reincidência.
Added
implant auto-ban service install/uninstall/start/stop/restart/status/logsimplant auto-ban scan [--dry-run]implant auto-ban list/events/offenses/offenses-clearimplant auto-ban allow/unallow/allow-listimplant auto-ban config show/path
Progressive backoff
1ª ofensa = base TTL. Dobra a cada reincidência. Cap em 16×. Após 5 ofensas vira permanente.
Never-ban (3 camadas)
RFC1918/loopback/link-local + IMPLANT_RL_WHITELIST + IMPLANT_AB_ALLOW.
Emergency-mode
Service entra em OPT_IN_FEATURES. emergency-disable para o service,
ipsets/offenses preservados, deadman restaura.
[2.21.0] - 2026-05-21
ipset infrastructure: whitelist migrada para ipset + blocklist nova como infra para v2.22.0 auto-ban e v2.23.0+ geo-block. State schema bump 1.0→2.0 com migração explícita.
Added (7 novos subcomandos)
implant rate-limit migrate-to-ipset— migração v1.0→v2.0 com snapshotimplant rate-limit block-ip --ip X [--ttl N]— bloqueia IP com TTL opcionalimplant rate-limit unblock-ip --ip Ximplant rate-limit blocklist-list/blocklist-clearimplant rate-limit block-list-from-file --file X [--ttl N] [--yes]— bulk-import auto-detect (JSON / CSV / text)implant rate-limit whitelist-list-from-file --file X [--yes]
Changed
- Backend de whitelist: ipset (mesma CLI, performance O(1))
- Topologia INPUT: BLOCKLIST[1] → WHITELIST[2] → RATELIMIT[3]
- State
schema_version1.0 → 2.0
Migração obrigatória (servidores em 2.20.0)
sudo implant rate-limit migrate-to-ipsetAnti-tijolar: faz snapshot do iptables antes de tudo. Fresh installs já usam ipset automaticamente.
Emergency-disable
Preserva ipsets entre disable/restore. TTLs continuam tickando.
[2.20.0] - 2026-05-21
Novo subcomando implant threat-status — coleta read-only de métricas
vivas (8 seções: conntrack, sockets, drops, fail2ban, log/auth, system,
services, hardening) com severity + detection de transitions.
Added
- Pack default: snapshot atual + grava JSONL local
- Subcomandos: snapshots / events / clear-history
- Flag
--no-recordpara dry-read - Histórico em JSONL bounded (~1.2MB max), sem rotação
Severity por seção (≥ inclusivo)
Conntrack ≥70% warn, ≥90% crit | SYN_RECV ≥1000/≥5000 | iptables drops ≥100/min, ≥1000/min | fail2ban bans ≥10/≥100 | SSH failed 5min ≥50/≥500 | Load ≥ncpu×2 / ≥ncpu×4 | Memory ≥80% / ≥95%.
Não inclui
- Envio dos snapshots para o console remoto (release separada)
- Auto-ban via ipset (v2.21.0)
[2.19.0] - 2026-05-21
Novo subcomando implant rate-limit — connection limits + rate limits
por porta via iptables.
Added
- Pack default: SSH 20conn+5/min, HTTP 50+200/min, HTTPS 50+200/min, ICMP 5/s
- Subcomandos: apply/revert/status/list + add/remove + whitelist-ip/unwhitelist-ip/whitelist-list
- Emergency-disable/restore/status (padrão v2.18.3)
- Integração com
emergency-mode—rate-limitagora emOPT_IN_FEATURES
Limitações
- Distro: Debian/Ubuntu apenas na v1
- Whitelist: iptables raw (migração para ipset em v2.20.0+ com threat-status)
[2.18.5] - 2026-05-21
Fixed
- Hotfix:
restore_cmddo deadman agora encadeia limpeza do state file (<feature> apply && rm -f <state-file>). Sem isso,emergency-mode statuscontinuava reportando entradas expiradas como ativas após o deadman disparar.
[2.18.4] - 2026-05-21
Fixed
- Hotfix:
emergency-disablefalhava comerror: unexpected argument '--quiet' found.lockdown_cmdagora usaimplant harden-network --quiet revert(flag antes do subcomando) — clap exige flags globais ANTES do positional.
[2.18.3] - 2026-05-21
Padrão emergency-disable para features opt-in + bypass guarantee
no deadman do SSH.
Added
<feature> emergency-disable/restore/statusem features opt-in (harden-networkagora). Desabilita temporariamente com TTL — re-aplica via deadman automático.implant emergency-mode enable/disable/status/heartbeat— comando global que itera features opt-in em uma operação.implant ssh-service cleanup-emergency-rules— remove bypass do iptables/ip6tables/UFW (idempotente).- Flag
--quietemharden-network apply/revert. - Flag
--forceemssh-service disable.
Changed
- SSH deadman agora prepend
iptables -I INPUT 1 -p tcp --dport <ssh_port> -j ACCEPT --comment 'implant-emergency-ssh'antes de iniciar o sshd. Garante que rate-limit/firewall/iptables não bloqueiem o retorno.
[2.18.2] - 2026-05-20
Fixes em dois bugs do fluxo --dry-run + inclusão do conntrack nas
ferramentas essenciais.
Fixed
- Crítico: módulo
appsignorava--dry-run—check --auto-fix --dry-runbaixava e instalava os apps deimplant installde verdade. Fix: early return emdry_runnas 5 funções de install. - UX: resumo do dry-run dizia "nenhuma mudança seria realizada"
mesmo quando teria 12 fixes pendentes. O filtro só contava
Fail, mas em dry-run os itens ficam marcadosFixed(executor intercepta os comandos, código Rust segue pro success path). Fix: aceitarFail || Fixedno summary.
Added
conntrack(pacote Debian/Ubuntu) na lista de ferramentas essenciais. Necessário paraconntrack -C/conntrack -Lem debug de incidente com saturação da tabela.
[2.18.1] - 2026-05-13
Extensão do pack --harden-network com sysctls adicionais (defense-in-depth).
Sem mudanças em comandos — apenas mais proteções no mesmo
/etc/sysctl.d/99-harden-network.conf.
Added
Conntrack timeouts (se Docker/K3s):
nf_conntrack_tcp_timeout_syn_recv = 10— anti SYN flood na tabelanf_conntrack_tcp_timeout_syn_sent = 10nf_conntrack_tcp_timeout_close_wait = 30nf_conntrack_tcp_timeout_fin_wait = 30nf_conntrack_tcp_timeout_time_wait = 30
Anti TIME_WAIT assassination:
net.ipv4.tcp_rfc1337 = 1(RFC 1337)
TCP keepalive (detecta zumbis em 10min, default 2h):
tcp_keepalive_time = 600tcp_keepalive_intvl = 30tcp_keepalive_probes = 5
Resource exhaustion protection:
vm.swappiness = 10vm.overcommit_memory = 2+vm.overcommit_ratio = 80vm.panic_on_oom = 0
[2.18.0] - 2026-05-13
Pack opt-in de hardening de rede estendido. Cobre 3 gaps do hardening base: IPv6 desprotegido (sysctls v4-only), sem tuning anti SYN flood, e TIME_WAIT acumulando.
Added
- Subcomando
implant harden-network apply/revert/status— padrão granular dos outros controles. Reversível independentemente do hardening base. - Flag
--harden-networkemimplant check— aplica o pack junto com o auto-fix. Requer--auto-fix(caso contrário é ignorado com warning, porque é destrutivo).
Pack aplicado (`/etc/sysctl.d/99-harden-network.conf`)
| Sysctl | Valor | Por quê |
|---|---|---|
net.ipv6.conf.all.accept_redirects |
0 |
Espelho do v4 — anti ICMPv6 redirect hijack |
net.ipv6.conf.all.accept_source_route |
0 |
Espelho do v4 |
net.ipv4.tcp_max_syn_backlog |
8192 |
Fila maior contra SYN flood |
net.core.somaxconn |
65535 |
Backlog de accept() para serviços |
net.ipv4.tcp_synack_retries |
2 |
Janela menor de retransmissão |
net.ipv4.tcp_fin_timeout |
15 |
Recicla TIME_WAIT mais rápido |
net.ipv4.tcp_tw_reuse |
1 |
Reuso de sockets em TIME_WAIT |
net.netfilter.nf_conntrack_max |
524288 |
Apenas se Docker/K3s detectado |
[2.17.2] - 2026-05-13
Quatro bugs descobertos rodando implant check --auto-fix num Ubuntu 24.04
fresh. O mais crítico fazia todos os apt install do auto-fix falharem
silenciosamente.
Fixed
- Apt install nunca executava (crítico): aspas duplas literais em
echo "Matando processo apt stale..."dentro desh -c "..."aninhado quebravam o parse do shell, fazendo todos os pacotes faltantes do auto-fix retornarem exit 2 ("não encontrado") — disfarçando o problema como pacote ausente do repositório. O echo informacional foi removido. - Percentual
[2/2] 0%no resumo por módulo: a coluna[X/Y]somavapassed + fixed, mas o%só contavapassed. Módulos onde tudo foi corrigido mostravam0%. Fórmula corrigida. - Banner de ROLLBACK com zero ações: cada install que falhava
imprimia 6+ linhas de banner mesmo sem nada a reverter.
execute_rollbackagora retorna cedo seactions.is_empty(). Status Final: SUCESSOcom falhas residuais: o relatório confiava num campo stale do report. Agora derivaeffective_statuslocalmente das contagens (total_failed,total_fixed).
[2.17.1] - 2026-05-10
Rodada de UX no fluxo de check --auto-fix baseada em feedback de produção.
Fixed
- Aliases pra
--auto-fix:Commands::Checkaceita--auto,--fix,-acomo aliases. Operadores não batem mais em "unexpected argument" por digitar a forma curta natural. - Output de snapshot SSH compacto:
create_snapshotimprimia 11 sub-steps internos que poluíam o terminal. Agora imprime apenas▸ Criando snapshot SSH...no início e✓ Snapshot SSH em <path>no fim. Detalhe permanece emstate.jsonpara auditoria. - Display custom para
RollbackAction: log vazava{:?}do Rust em human output. Agora usaDisplayformatado, e movido deinfo!paradebug!— só verbose vê. - Exit codes semânticos:
(código: 127)virou(comando não disponível). Mapeamento: 1 falhou, 2 não encontrado, 126 permissão negada, 127 comando não disponível, 130 interrompido, 137 OOM, 143 SIGTERM. Verbose preserva o número. → Verificando Xsuprimido em human não-verbose: antes cada sub-check imprimia→antes e✓depois (duplicação visual). Só o resultado final aparece agora;--verbosepreserva ambos.
[2.17.0] - 2026-05-09
Rodada de integração com o console de gerenciamento remoto — controles granulares de hardening expostos via CLI estruturado, lockdown SSH com TTL e auto-recovery.
Added
- Primitiva genérica
lockdown: mecanismo opt-in de service-restriction com TTL e auto-recovery viasystemd-run. Recovery delegado ao systemd com shell puro — não depende do binário implant nem do agente de controle remoto estarem vivos. TTL cap hardcoded em 6h. Persistência atômica em/var/lib/implant/lockdowns/<service>.json. - Wrapper
ssh-service:implant ssh-service disable/heartbeat/status/emergency-restorecomo interface de alto nível pra restringir SSH. Detecta porta atual, montalockdown_cmd(ufw deny + systemctl stop) erestore_cmd(systemctl start + ufw allow). Emergency-restore exige TTY interativo. - Fail2ban granular (
implant fail2ban): list-jails, list-banned, ban, unban, clear, tail-log. Tudo viafail2ban-client. IPs validados comIpAddr::from_strantes de qualquer composição shell. - Subcomando
iptables: list, append, delete, flush, save, restore, snapshot — com salvaguardas anti-tijolar: snapshot automático antes de destrutivos (últimos 10 em/var/lib/implant/iptables-snapshots/), whitelist hardcoded de regras críticas (SSH, lo, ESTABLISHED) que recusa delete/flush, flush global exige TTY interativo. - Subcomando
statusconsolidado: leitura agregada do sistema com cache em/var/lib/implant/state.json(TTL 24h).--refreshforça re-execução do check. - Pin TLS do endpoint do console remoto: adicionado ao set de domínios pinados.
Notes
A integração do lado do console remoto (push de policy, indicadores e alertas) é distribuída separadamente.
[2.16.0] - 2026-05-08
Rodada de hardening pós-revisão de segurança.
Security
- TLS pinning real:
get_http_client()instala umServerCertVerifiercustom no rustls que valida chain via WebPKI e confronta o SPKI hash do leaf cert no mesmo handshake. Antes o pin era checado em conexão TLS separada, permitindo divergência entre a conexão de pin-check e a conexão da requisição real. - Cliente HTTP pinado para download de chave:
add_public_key_from_urldeixou de usarcurl/wgete passou a usar o cliente HTTP pinado. Rejeita schemes não-https. - Validação de IP em whitelist:
whitelist_ipvalidaIpAddr::from_strantes de qualquer composição de comando. Bloqueia entradas com newline, espaço, metacaracteres de shell ou strings não-IP. - K3s install via env vars:
K3S_TOKENeK3S_URLsão entregues viaCommand::envem vez de interpolados em string shell. - Validação de identifier:
add_key_to_authorized_keys,add_public_key_from_urleremove_keyrejeitam identifier fora de[A-Za-z0-9._-]{1,64}. init.shverifica.minisig: instalador baixa.minisigjunto com o binário, instalaminisign(apt/dnf+epel/yum+epel/apk) com fallback para binário static do GitHub validado por SHA-256, e só instala se a assinatura bater.
Fixed
- Bug do backup
.bak: 7 call sites emssh_port.rs,reset.rs,fundamentals.rsetraefik.rstentavam restaurar de{path}.bak, masexecutor.backup_file()cria{path}.backup.{timestamp}. O fallback nunca funcionava na prática. - Self-update atômico: substitui
fs::remove_file+fs::copyporfs::renameúnico. Elimina a janela onde o binário/symlink ficava inexistente. confirm()exige TTY: detecta stdin não-interativo viaIsTerminale auto-recusa com aviso explícito.
[2.14.8] - 2026-04-19
Fixed
- apt: Simplifica
apt-get updatesem nesting desh -c
[2.14.7] - 2026-04-19
Fixed
- apt: Para
unattended-upgradesdurante instalacao + timeout noapt-get update
[2.14.6] - 2026-04-19
Fixed
- apt: Mata processos apt stale (>30min) + wait lock max 60s
[2.14.5] - 2026-04-19
Fixed
- needrestart: Configuracao via
/etc/needrestart/conf.d/drop-in (modo list-only)
[2.14.4] - 2026-04-19
Fixed
- needrestart: Drop-in config para needrestart, iotop e iftop restaurados
[2.14.3] - 2026-04-19
Fixed
- install: Timeout 120s em
install_package, removido iftop
[2.14.2] - 2026-04-19
Fixed
- install: Removido iotop (travava em Ubuntu 22.04+)
[2.14.1] - 2026-04-19
Fixed
- security: Timeout 10s no TCP connect + TLS handshake do
extract_and_verify_pin
[2.14.0] - 2026-04-19
Added
- multi-arch: Release estavel com static musl para x86_64 e aarch64
- security: TLS Pinning (SPKI) com pins compilados para as CDNs oficiais do implant e dos apps instaláveis
- security: Guardrail hardened com allowlist de hostname
implant.ccs.systems+ verificacao de pin - self-update: URLs arch-aware para self-update e instalacao de subsistemas
- build: Makefile +
build_multiarch.sh+Cross.tomlpara build multi-arch - build: Cargo.toml otimizado (tokio sem "full", opt-level=z, panic=abort)
- gitops:
.gitops.ymlv2.0 com artifacts multi-arch explicitos - init.sh: Deteccao de arquitetura + flag
--rcpara release candidates
[2.14.0-rc.3] - 2026-04-02
Added
- ssh-rollback: Novo comando para listar e restaurar snapshots SSH
- Snapshots automaticos antes de qualquer modificacao SSH
- Salva sshd_config, socket override, fail2ban, sysctl
- Ate 10 snapshots com rotacao automatica
- emergency-reset: Reverte TODAS as configs de seguranca (7 passos independentes)
- Porta SSH → 22, firewall aberta, hardening removido, fail2ban desabilitado
- Preserva ip_forward quando Docker/K3s presente
- watchdog SSH: Reversao automatica em 5 minutos se porta nao confirmada
- Backend:
at(preferido) ousystemd-run(fallback) - Confirmar com
implant ssh-port --confirm-change
- Backend:
- ssh-port: Confirmacao obrigatoria antes de alterar (
--yespara skip) - reset: Flag
--yespara pular confirmacao
Fixed
- CRITICO:
reset --ssh-porthardcodava porta 2222 (agora detecta dinamicamente) - CRITICO:
reset --ssh-portnao suportava systemd socket activation - CRITICO:
reset --ssh-portnao validava sshd_config antes de restart - CRITICO:
reset --ssh-portnao abria firewall antes de alterar - reset --ssh-hardening: Adicionado backup + validacao sshd -t + fallback chain
- reset --kernel-hardening: Preserva ip_forward=1 quando Docker/K3s detectado
[2.14.0-rc.2] - 2026-03-26
Added
- traefik-accesslog: Confirmacao antes de aplicar mudancas
- traefik-accesslog: Deteccao de Traefik via DeployAlly e Docker Compose
- traefik-accesslog: Adicao automatica de volume de log
- ssh-port: Modo status (sem argumento mostra porta atual e conexoes)
[2.14.0-rc.1] - 2026-03-26
Added
- traefik-accesslog: Novo comando para configurar access log do Traefik
- ssh-port: Refatorado para status/change separados
Fixed
- CRITICO: Hardening setava ip_forward=0 quebrando Docker/K3s
- fundamentals: SSH settings inseridas antes de Include/Match
- fundamentals: Validacao sshd -t antes de restart com auto-restore
[2.13.1] - 2026-03-18
Fixed
- install backupally: URL atualizada
[2.12.10] - 2026-03-08
Fixed
- install apps: Limpa arquivo temporario residual de outro usuario antes de baixar
- install apps: Mensagens de erro detalhadas com contexto (qual operacao falhou)
[2.12.9] - 2026-03-08
Fixed
- install apps: Mensagens de erro com contexto detalhado em cada operacao
[2.12.8] - 2026-03-03
Fixed
- self-update/install: Troca
fs::renameporfs::copy+removepara suportar cross-device- Corrige erro "Invalid cross-device link" (os error 18) quando
/tmpe tmpfs - Garante
chmod 755apos copy
- Corrige erro "Invalid cross-device link" (os error 18) quando
[2.12.7] - 2026-02-28
Changed
- install claude-code: Usa instalador nativo oficial (
curl -fsSL https://claude.ai/install.sh | bash)- Remove dependencia de NVM/Node.js como pre-requisito
- Auto-update automatico em background
[2.12.6] - 2026-02-28
Added
- ssh-key: Flag
--aliaspara definir nome do alias
[2.12.0] - 2026-02-28
Changed
- BREAKING: Modulo
ssh-keycompletamente refatorado- Modelo simplificado: servidor central distribui sua chave publica
- Removida logica de geracao de chaves no servidor gerenciado
Added
- ssh-key:
--add-public-key "ssh-ed25519 AAAA..."- Adiciona chave publica - ssh-key:
--add-public-key-url "https://..."- Busca chave de URL - ssh-key:
--list- Lista chaves no authorized_keys - ssh-key:
--remove "identificador"- Remove chave - ssh-key:
--whitelist-ip IP- Adiciona IP a whitelist
[2.11.6] - 2026-02-27
Fixed
- self-update: Corrige erro "Text file busy" (os error 26)
[2.11.2] - 2026-02-27
Fixed
init.sh: Usa binario direto ao inves de .zipinit.sh: Corrige flag--autopara--auto-fix
[2.11.1] - 2026-02-27
Added
init.sh: Script de instalacao rapida- GitOps:
init.shadicionado como artifact
[2.10.2] - 2025-02-17
Fixed
- CRITICO: Liberar porta no UFW/iptables ANTES de alterar SSH
- Evita lockout do servidor quando firewall esta habilitado
[2.10.0] - 2025-02-13
Added
setup-claudecode: Configura usuario dedicado para Claude Code
- Cria usuario
claudecodecom grupo proprio - Sudoers granulares ou irrestrito
- ACLs em diretorios de trabalho
- Guard-rail CLAUDE.md com auto-update
- Cria usuario
update-guardrail: Gerencia guard-rails remotos
[2.9.0] - 2025-02-12
Added
- Suporte a systemd socket activation para SSH (Ubuntu 22.04+)
- SSH PerSourcePenalties para OpenSSH 9.8+
- Whitelist automatico de IP da conexao atual
[2.3.9] - 2024-12-28
Added
- Logrotate automatico baseado no tamanho do disco
[2.3.8] - 2024-12-28
Added
- Sistema de instalacao de apps externos (DeployAlly, Runner, etc)
[1.0.0] - 2024-11-29
Added
- Release inicial
- Modulos: fundamentals, hardening, docker, network, monitoring
- Modo dry-run e auto-fix
- Rollback automatico
- Multi-distro (Ubuntu, Debian, CentOS, Rocky Linux)
- Self-update