Resumo: se os pacotes Syslog do FortiGate chegam ao container, mas o arquivomessagesnão é criado, o problema pode estar no perfil do AppArmor aplicado aorsyslogd. Neste guia, você acompanha o diagnóstico por camadas e aplica uma exceção com o menor privilégio necessário.
Ao implantar o Cloud Discovery do Microsoft Defender for Cloud Apps, um dos principais objetivos é identificar aplicações em nuvem utilizadas dentro da organização, inclusive serviços que não foram formalmente aprovados pela TI — o conhecido Shadow IT.
Para isso, o Microsoft Defender pode receber os logs de navegação gerados por firewalls e proxies. Em uma arquitetura com FortiGate, um modelo comum é encaminhar os eventos de tráfego para um Log Collector executado em um container Docker no Linux. O coletor recebe os eventos por Syslog, processa os arquivos e os envia ao portal do Microsoft Defender.
Em teoria, o fluxo é simples:
FortiGate → Syslog UDP/514 → Docker → rsyslog → arquivo messages → processamento → Microsoft Defender
Na prática, uma política de segurança do próprio Linux pode interromper silenciosamente esse processo.
Este artigo apresenta um caso real em que:
- o FortiGate estava enviando os logs;
- os pacotes chegavam ao container;
- a porta UDP/514 estava aberta;
- o coletor conseguia se comunicar com o portal da Microsoft;
- mas nenhum evento era processado ou enviado.
A causa não estava no firewall, na rede, no Docker ou no Microsoft Defender. O bloqueio era provocado por um perfil do AppArmor aplicado ao processo rsyslogd.
Nota de atualização (agosto de 2026): a documentação atual da Microsoft mostra--security-opt apparmor:unconfinedno exemplo de implantação do coletor. Se o seu comando já utiliza essa opção, confirme o perfil efetivamente aplicado ao processo antes de alterar o AppArmor. O caso descrito neste artigo trata de um ambiente em que orsyslogdaparecia comorsyslogd (enforce).
Entendendo a arquitetura do Log Collector
O Log Collector do Defender for Cloud Apps é executado como um container. No caso do Syslog, o fluxo interno ocorre, de forma simplificada, da seguinte maneira:
- O firewall envia um evento Syslog para o endereço IP e a porta configurados.
- O Docker encaminha o pacote para a porta correspondente dentro do container.
- O
rsyslogdrecebe o evento. - Um ruleset direciona o evento para um arquivo chamado
messages. - O componente de processamento do coletor interpreta e compacta o arquivo.
- O arquivo é enviado ao Microsoft Defender for Cloud Apps pela porta TCP/443.
A própria documentação do rsyslog apresenta a associação entre uma entrada UDP, um ruleset e uma ação omfile, responsável pela gravação dos eventos em arquivo. Rsyslog — configuração de um servidor remoto
No Log Collector, o arquivo de entrada fica normalmente neste caminho:
/var/adallom/syslog/<porta-da-fonte>/messages
Para uma fonte configurada na UDP/514:
/var/adallom/syslog/514/messages
Esse detalhe é importante porque receber o pacote na interface de rede não significa que o processo conseguiu gravá-lo em disco.
O sintoma inicial
O primeiro sinal do problema apareceu no comando de status do coletor:
sudo docker exec <NOME_DO_COLETOR> \
collector_status -p
O resultado indicava:
General information:
Files uploaded: 0
Status: OK
Data sources:
Last log received: Not yet received
Number of logs received: 0
Em determinado momento, depois do reinício, o status também passou temporariamente para:
Status: Error
Embora o coletor conseguisse se conectar ao portal, nenhum arquivo havia sido enviado e nenhuma fonte apresentava eventos recebidos.
Um erro comum nesse momento seria partir diretamente para alterações no FortiGate, recriar o container ou modificar a fonte no portal. Antes disso, porém, era necessário descobrir exatamente em qual etapa do fluxo o evento estava sendo interrompido.
Status “OK” não comprova que os logs estão sendo processados
O status do coletor precisa ser interpretado com cuidado.
Um resultado Status: OK indica que os componentes principais estão ativos e que o coletor consegue executar suas verificações internas. Também é possível que ele esteja se comunicando normalmente com o portal.
Isso não prova, isoladamente, que:
- o FortiGate está enviando eventos;
- os pacotes chegam ao container;
- o
rsyslogdconsegue gravá-los; - o formato dos eventos é reconhecido;
- o arquivo atingiu o tamanho necessário para upload;
- os dados já foram processados pelo Defender.
A análise precisa validar cada camada separadamente.
Etapa 1: validar o container e as portas publicadas
Primeiro, é necessário confirmar se o container está ativo:
sudo docker ps --filter name=<NOME_DO_COLETOR>
A saída deve apresentar o container em execução e a porta Syslog publicada, por exemplo:
0.0.0.0:514->514/udp
Isso confirma que o Docker está expondo a UDP/514 do host para a UDP/514 do container.
Também é importante consultar os logs do container:
sudo docker logs \
--since 15m \
--timestamps \
<NOME_DO_COLETOR>
Nesse ponto, deve-se procurar erros de inicialização, conectividade, armazenamento, permissão ou processamento.
Etapa 2: confirmar que os pacotes chegam ao container
O próximo passo é verificar se o FortiGate realmente está entregando os eventos.
Uma forma precisa de realizar essa validação é obter o PID do container e executar o tcpdump dentro do seu namespace de rede:
container_pid=$(sudo docker inspect \
--format '{{.State.Pid}}' \
<NOME_DO_COLETOR>)
Depois:
sudo nsenter -t "$container_pid" -n \
tcpdump -ni any udp port 514
Se aparecerem pacotes contendo campos típicos do FortiGate, como estes:
devname=
type="traffic"
subtype="forward"
srcip=
dstip=
fica comprovado que:
- o FortiGate está enviando;
- o caminho de rede está funcionando;
- a porta está acessível;
- o Docker está entregando os pacotes ao container.
A partir desse momento, continuar alterando policies, rotas ou configurações Syslog do FortiGate provavelmente não ajudará. O diagnóstico deve avançar para dentro do container.
Etapa 3: verificar o listener do rsyslog
É necessário confirmar que o rsyslogd está ouvindo na porta definida para a fonte:
sudo nsenter -t "$container_pid" -n \
ss -lunp | grep ':514'
O processo esperado é o rsyslogd.
Também é possível confirmar sua execução:
sudo docker exec <NOME_DO_COLETOR> \
ps -eo user,pid,cmd | grep '[r]syslogd'
Nesse caso, tanto o processo Java do coletor quanto o rsyslogd estavam ativos.
Isso eliminou a hipótese de que o serviço estivesse parado. Ainda faltava descobrir se o evento recebido conseguia chegar ao arquivo de destino.
Etapa 4: inspecionar o arquivo messages
A Microsoft orienta verificar diretamente se os eventos Syslog estão sendo gravados no arquivo messages:
sudo docker exec <NOME_DO_COLETOR> \
ls -la /var/adallom/syslog/514
E, se o arquivo existir:
sudo docker exec <NOME_DO_COLETOR> \
tail -n 10 /var/adallom/syslog/514/messages
No ambiente analisado, o diretório existia, mas estava vazio:
/var/adallom/syslog/514/
O arquivo abaixo não era criado:
/var/adallom/syslog/514/messages
Essa constatação reduziu significativamente o escopo da investigação. Os eventos chegavam à rede do container, mas não eram persistidos pelo rsyslog.
Um teste interno para eliminar a rede da equação
Para confirmar que a falha era interna, foi gerado um evento diretamente dentro do container:
sudo docker exec <NOME_DO_COLETOR> \
logger -n 127.0.0.1 -P 514 -d \
-p local7.notice \
'TESTE-RSYSLOG-INTERNO'
Depois:
sudo docker exec <NOME_DO_COLETOR> \
sh -c '
sleep 2
test -f /var/adallom/syslog/514/messages &&
tail -n 5 /var/adallom/syslog/514/messages ||
echo "Arquivo messages não foi criado"
'
O arquivo continuou ausente.
Esse teste foi decisivo: mesmo um evento gerado localmente, sem depender do FortiGate, da rede física ou do encaminhamento entre equipamentos, não era gravado.
Portanto, a falha estava entre:
rsyslogd → ruleset → criação do arquivo
A mensagem que revelou a causa
Ao analisar os logs internos, apareceu o erro:
file '/var/adallom/syslog//514/messages':
open error: Permission denied
Em um primeiro momento, uma mensagem Permission denied normalmente direciona a investigação para:
- proprietário do diretório;
- grupo;
- permissões de leitura e escrita;
- ACL;
- sistema de arquivos somente leitura;
- usuário usado pelo processo.
Mas as permissões Unix não explicavam o comportamento.
O rsyslogd estava executando como root, e o diretório também pertencia a root.
Foi então realizado um teste de escrita comum:
sudo docker exec <NOME_DO_COLETOR> \
touch /var/adallom/syslog/514/teste-escrita-root
O arquivo foi criado com sucesso.
Isso produziu uma evidência importante:
O sistema de arquivos aceitava escrita e o usuário root tinha permissão. O bloqueio era específico para o processo rsyslogd.
Root não ignora todas as políticas de segurança
No Linux, executar como root não significa ter liberdade absoluta.
Mecanismos de controle de acesso obrigatório, como AppArmor e SELinux, podem restringir um processo mesmo quando ele é executado pelo usuário root. Essas políticas avaliam o perfil atribuído ao processo e os recursos que ele está autorizado a acessar.
Para verificar o perfil aplicado ao rsyslogd, foi executado:
sudo docker exec <NOME_DO_COLETOR> \
sh -c '
rsyslog_pid=$(pgrep -o rsyslogd)
cat "/proc/$rsyslog_pid/attr/current"
'
O resultado foi:
rsyslogd (enforce)
Isso demonstrou que o processo estava confinado por um perfil chamado rsyslogd, em modo de aplicação efetiva.
No modo enforce, o AppArmor não apenas registra operações fora da política: ele efetivamente as bloqueia.
A documentação do Docker explica que o AppArmor pode aplicar perfis aos processos dos containers e recomenda utilizar dmesg e aa-status durante o diagnóstico. Docker — AppArmor security profiles
Confirmando o bloqueio no log do kernel
A confirmação definitiva veio do log de auditoria do kernel:
sudo journalctl -k \
--since "30 minutes ago" \
--no-pager |
grep -iE 'apparmor="DENIED"|profile="rsyslogd"|/var/adallom'
A saída apresentou eventos como:
apparmor="DENIED"
operation="mkdir"
profile="rsyslogd"
name="/var/adallom/syslog/514/"
requested_mask="c"
denied_mask="c"
Essa mensagem contém todas as informações necessárias:
apparmor="DENIED": a operação foi negada pelo AppArmor;operation="mkdir": o processo tentou criar um diretório;profile="rsyslogd": o perfil responsável foi o do rsyslog;name="/var/adallom/syslog/514/": o objeto bloqueado era o diretório do coletor;requested_mask="c": o processo solicitou permissão de criação.
Mesmo que o diretório fosse criado manualmente, o processo ainda precisaria de autorização para criar e escrever o arquivo messages.
A correção: uma exceção restrita no perfil
A solução não foi desativar o AppArmor nem colocar o perfil inteiro em modo permissivo. Isso reduziria a segurança do sistema e esconderia o verdadeiro conflito.
A abordagem correta foi criar uma autorização limitada ao diretório utilizado pelo Log Collector.
Primeiro, é necessário localizar o perfil:
sudo grep -Rns \
'profile.*rsyslogd\|usr/sbin/rsyslogd\|local/usr.sbin.rsyslogd' \
/etc/apparmor.d 2>/dev/null
Em instalações Ubuntu, o perfil normalmente está relacionado a:
/etc/apparmor.d/usr.sbin.rsyslogd
Antes de criar a exceção, deve-se confirmar se o perfil principal inclui o arquivo de customização local:
sudo grep -n 'local/usr.sbin.rsyslogd' \
/etc/apparmor.d/usr.sbin.rsyslogd
A entrada esperada é semelhante a:
#include <local/usr.sbin.rsyslogd>
A customização pode então ser adicionada ao arquivo:
/etc/apparmor.d/local/usr.sbin.rsyslogd
Para um ambiente com apenas a UDP/514, uma regra mais restrita pode considerar o diretório pai e a fonte específica:
# Microsoft Defender for Cloud Apps Log Collector
/var/adallom/syslog/ rw,
/var/adallom/syslog/514/ rw,
/var/adallom/syslog/514/** rw,
Se o servidor possuir diferentes fontes em portas distintas e o próprio coletor precisar criar dinamicamente essas estruturas, pode ser necessário autorizar o conteúdo do diretório Syslog:
# Microsoft Defender for Cloud Apps Log Collector
/var/adallom/syslog/ rw,
/var/adallom/syslog/** rw,
A segunda opção é mais abrangente. Portanto, deve ser utilizada apenas quando houver necessidade operacional comprovada.
As regras de arquivo do AppArmor permitem definir permissões sobre caminhos e utilizar padrões para abranger objetos subordinados. Ubuntu Manpages — sintaxe dos perfis AppArmor
Validando e recarregando o perfil
Depois da alteração, é importante validar a sintaxe antes de recarregar o perfil:
sudo apparmor_parser -Q \
/etc/apparmor.d/usr.sbin.rsyslogd
Se nenhum erro for apresentado:
sudo apparmor_parser -r \
/etc/apparmor.d/usr.sbin.rsyslogd
O perfil deve permanecer ativo:
sudo aa-status | grep rsyslogd
Não é necessário desativar o AppArmor nem reiniciar todo o servidor.
Depois, o processo rsyslogd do container pode ser reiniciado:
sudo docker exec <NOME_DO_COLETOR> \
supervisorctl restart rsyslog
Testando a correção
Um novo evento interno deve ser gerado:
sudo docker exec <NOME_DO_COLETOR> \
logger -n 127.0.0.1 -P 514 -d \
-p local7.notice \
'TESTE-RSYSLOG-APPARMOR-CORRIGIDO'
Em seguida:
sudo docker exec <NOME_DO_COLETOR> \
sh -c '
sleep 2
ls -lh /var/adallom/syslog/514/messages
tail -n 10 /var/adallom/syslog/514/messages
'
O resultado esperado é encontrar a mensagem:
TESTE-RSYSLOG-APPARMOR-CORRIGIDO
Também é necessário verificar se não foram geradas novas negações:
sudo journalctl -k \
--since "5 minutes ago" \
--no-pager |
grep -iE 'apparmor="DENIED".*profile="rsyslogd"|/var/adallom'
Se não houver novos eventos DENIED e o arquivo messages estiver sendo preenchido, o bloqueio foi resolvido.
Quando os eventos começam a ser enviados ao Defender?
Depois da correção, o arquivo messages passou a receber conteúdo real do FortiGate. Ainda assim, os contadores podiam continuar temporariamente em zero:
Files uploaded: 0
Number of logs received: 0
Isso não significa necessariamente que o problema continua.
No modo Syslog, o Log Collector grava os eventos em disco até o arquivo superar aproximadamente 40 KB. Depois disso, o arquivo é processado e enviado ao Defender for Cloud Apps. Após o upload, uma cópia pode ser consultada no diretório de backup:
/var/adallom/discoverylogsbackup
Esse comportamento é documentado oficialmente pela Microsoft. Microsoft Learn — upload automático para relatórios contínuos e gerenciamento avançado do Log Collector
O crescimento do arquivo pode ser acompanhado com:
sudo docker exec <NOME_DO_COLETOR> \
ls -lh /var/adallom/syslog/514/messages
E o status:
sudo docker exec <NOME_DO_COLETOR> \
collector_status -p
Depois do processamento, o resultado esperado é semelhante a:
Files uploaded: 1
Status: OK
Last log received: <data e hora>
Number of logs received: <valor maior que zero>
Um problema paralelo: dimensionamento do servidor
Durante o diagnóstico, também foi identificado que o servidor possuía aproximadamente 22 GB de armazenamento total disponível ao container.
Esse volume estava abaixo do requisito oficial da Microsoft, que atualmente indica:
- 250 GB de espaço em disco;
- 2 núcleos de CPU;
- arquitetura Intel 64 ou AMD 64;
- 4 GB de memória RAM.
A insuficiência de disco não foi a causa imediata do bloqueio de escrita, pois a negação foi comprovadamente produzida pelo AppArmor. Entretanto, manter o ambiente abaixo dos requisitos pode provocar descarte de logs, falhas futuras de processamento e colocar a implantação fora da configuração suportada pela Microsoft. Microsoft Learn — requisitos do Log Collector no Linux
Um diagnóstico bem executado também deve registrar problemas paralelos, mesmo quando eles não explicam o incidente atual.
O que não deveria ser feito
Durante esse tipo de investigação, algumas “soluções rápidas” podem criar novos riscos:
Aplicar chmod 777
Se o processo já executa como root e um mecanismo de controle obrigatório está negando a operação, ampliar as permissões Unix não resolverá o problema. Além disso, permitirá que outros usuários ou processos escrevam no diretório.
Desativar o AppArmor
Desabilitar o AppArmor pode fazer o erro desaparecer, mas remove uma camada de proteção de todo o sistema. O melhor caminho é autorizar somente os objetos necessários.
Executar o container permanentemente como privilegiado
Aumentar indiscriminadamente as capacidades do container amplia sua superfície de ataque e pode não resolver um perfil específico aplicado ao processo.
Recriar o coletor antes de entender a causa
A recriação pode apagar evidências e repetir exatamente o mesmo problema, especialmente quando a política responsável está carregada no host.
Alterar repetidamente o FortiGate
Depois que o tcpdump confirma os eventos dentro do container, o foco deve sair do firewall e avançar para o processamento interno.
Método recomendado de diagnóstico
A principal lição deste caso é investigar o fluxo por camadas:
- Verificar se o container está ativo.
- Confirmar as portas publicadas.
- Validar a comunicação com o portal.
- Capturar os pacotes dentro do namespace do container.
- Confirmar que o
rsyslogdestá ouvindo. - Verificar a existência e o crescimento do arquivo
messages. - Gerar um evento local para eliminar dependências externas.
- Procurar erros de gravação nos logs.
- Comparar a escrita de um processo comum com a escrita do serviço.
- Consultar AppArmor, SELinux, ACLs e outras políticas de confinamento.
- Aplicar uma exceção baseada no menor privilégio.
- Repetir os testes e confirmar a ausência de novas negações.
- Aguardar o arquivo atingir o limite de processamento.
- Validar o upload e a interpretação dos eventos no portal.
A orientação de troubleshooting da Microsoft segue a mesma lógica geral: verificar a associação da fonte ao coletor, confirmar o protocolo e a porta, validar a chegada dos eventos e garantir a comunicação de saída pela TCP/443. Microsoft Learn — solução de problemas do Cloud Discovery
Conclusão
O aspecto mais interessante deste incidente foi que quase todos os componentes aparentavam estar funcionando:
- o FortiGate enviava os eventos;
- os pacotes chegavam ao container;
- a UDP/514 estava aberta;
- o
rsyslogdestava ativo; - o coletor se conectava ao portal;
- o diretório existia;
- o usuário root conseguia escrever nele.
Ainda assim, o fluxo estava interrompido.
A causa somente ficou evidente quando a análise deixou de tratar Permission denied como uma simples permissão de arquivo e passou a considerar os controles de acesso obrigatórios do Linux.
O AppArmor cumpria exatamente a sua função: impedia que um processo escrevesse fora dos caminhos previstos pelo seu perfil. O problema estava na incompatibilidade entre a política aplicada ao rsyslogd e o diretório utilizado pelo Log Collector.
A correção adequada não foi remover a proteção, mas ajustar a política com o menor privilégio necessário.
Esse caso reforça uma regra valiosa para troubleshooting de infraestrutura e segurança: acompanhe o dado de ponta a ponta e valide cada transição do fluxo. Quando o pacote chega à interface, mas não aparece na aplicação, a rede pode já ter feito seu trabalho. O problema pode estar na próxima camada — e, algumas vezes, na própria proteção criada para manter o ambiente seguro.