5 pontos por GN⁺ 2025-08-20 | 1 comentários | Compartilhar no WhatsApp
  • O systemd oferece recursos poderosos de gerenciamento de serviços, mas a configuração padrão é otimizada mais para usabilidade do que para segurança, por isso é necessário aplicar opções adicionais de hardening
  • Com o comando systemd-analyze security, é possível analisar os indicadores de exposição de segurança de todos os serviços ou de um serviço específico e definir prioridades
  • Existem várias opções de segurança que podem ser aplicadas no nível da unidade de serviço, e elas podem ser ajustadas individualmente por meio de /etc/systemd/system/ServiceName.service.d/override.conf e afins
  • Entre as principais opções estão ProtectSystem, PrivateTmp, NoNewPrivileges, SystemCallFilter, MemoryDenyWriteExecute e outras que restringem privilégios de processos e acesso a recursos
  • Em vez de buscar segurança perfeita, é mais eficaz priorizar o hardening de serviços expostos externamente para reduzir riscos, e isso também pode trazer grande efeito em ambientes self-hosting

Visão geral do systemd

  • O systemd oferece uma abordagem muito madura e robusta para gerenciamento de serviços
  • No entanto, como prioriza a usabilidade imediata mais do que a segurança, a configuração padrão é relativamente permissiva
  • Este documento apresenta várias opções de reforço de segurança que podem ser aplicadas a unidades de serviço do systemd e ao podman quadlet, para reduzir a possibilidade de comprometimento e minimizar o impacto caso ele ocorra
  • Não se trata de um guia para aplicar tudo de forma uniforme a todos os serviços; é necessário experimentar, verificar logs e ajustar individualmente conforme as características e os requisitos de cada serviço
  • A responsabilidade pela segurança da infraestrutura é totalmente do operador, e este documento serve como ferramenta de referência

Análise de segurança do systemd

  • Com o comando systemd-analyze security, é possível verificar o estado geral de segurança dos serviços ou analisar em detalhe as configurações de um serviço específico (por exemplo, sshd.service)
    • A saída inclui status de verificação, nome do recurso, descrição e pontuação de Exposure; quanto maior o Exposure, maior o risco
  • As opções de segurança podem ser adicionadas na seção [Service] (systemd) ou na seção [Container] (podman quadlet)
  • Recomenda-se usar systemctl edit ServiceName.service para criar um arquivo override; se houver falha, é preciso verificar as permissões necessárias e ajustá-las

Opções de segurança para serviços

  • O systemd fornece várias palavras-chave de opções de segurança, que podem ser consultadas em man systemd.exec 5, man capabilities 7 e afins
  • Algumas opções representativas relacionadas à segurança
    • ProtectSystem → opção para restringir o sistema de arquivos a somente leitura
    • ProtectHome → opção para bloquear acesso a /home, /root, /run/user
    • PrivateDevices → opção para bloquear acesso a dispositivos físicos e permitir apenas dispositivos virtuais como /dev/null
    • ProtectKernelTunables, ProtectKernelModules, ProtectKernelLogs → opções para bloquear acesso a recursos do kernel
    • NoNewPrivileges → opção para impedir obtenção de novos privilégios via setuid/setgid etc.
    • MemoryDenyWriteExecute → bloqueia o uso simultâneo de memória gravável e executável; pode causar problemas em algumas linguagens com JIT
    • SystemCallFilter → opção para restringir as system calls permitidas; em caso de violação, o processo pode ser encerrado ou receber retorno EPERM

Explicação de cada opção

  • ProtectSystem: com strict, monta todo o sistema de arquivos como somente leitura; /dev, /proc, /sys exigem opções de proteção separadas
  • ReadWritePaths: permite reabilitar escrita apenas em alguns caminhos
  • ProtectHome: bloqueia acesso a /home, /root, /run/user
  • PrivateDevices: desativa acesso a dispositivos físicos, permitindo apenas pseudo-dispositivos como /dev/null
  • ProtectKernelTunables: trata /proc, /sys como somente leitura
  • ProtectControlGroups: permite apenas acesso de leitura a cgroups
  • ProtectKernelModules: proíbe carregamento explícito de módulos do kernel
  • ProtectKernelLogs: restringe acesso ao buffer de logs do kernel
  • ProtectProc: com invisible, oculta em /proc/ processos pertencentes a outros usuários
  • ProcSubset: bloqueia em /proc conteúdos fora de itens relacionados a PID específicos
  • NoNewPrivileges: bloqueia nova elevação de privilégios via setuid, setgid e capabilities do sistema de arquivos
  • ProtectClock: bloqueia escrita no relógio do sistema/hardware
  • SystemCallArchitectures: com native, permite apenas syscalls nativas, como x86-64
  • RestrictNamespaces: restringe namespaces voltados a contêineres
  • RestrictSUIDSGID: bloqueia a configuração de bits setuid e setgid em arquivos
  • LockPersonality: impede mudança do domínio de execução (necessário apenas em aplicações antigas)
  • RestrictRealtime: restringe escalonamento em tempo real (necessário apenas para alguns serviços muito específicos)
  • RestrictAddressFamilies: restringe as famílias de endereços de socket permitidas (por exemplo, AF_INET, AF_INET6, AF_UNIX etc.)
  • MemoryDenyWriteExecute: bloqueia a criação adicional de regiões de memória graváveis e executáveis ao mesmo tempo (serviços com JIT exigem cuidado)
  • ProtectHostname: proíbe uso das syscalls sethostname e setdomainname
  • SystemCallFilter: define permissão/bloqueio de syscalls por serviço, com filtragem detalhada
    • É possível ajustar grupos, syscalls individuais e modos de permissão/bloqueio
    • Também há suporte para retornar códigos de erro como EPERM em vez de encerrar em caso de violação
    • A lista completa pode ser consultada em systemd-analyze syscall-filter ou man systemd.exec(5)
    • É possível negar toda a lista com o prefixo ~ (ex.: CapabilityBoundingSet=~CAP_SETUID etc.)

Processo de ajuste das restrições de SystemCallFilter

  • Com auditd, é possível verificar nos logs quais syscalls foram bloqueadas quando um serviço falha
    • Execute sudo ausearch -i -m SECCOMP -ts recent e verifique o valor da syscall
    • Em seguida, adicione essa syscall ou um grupo relacionado em SystemCallFilter para resolver o problema gradualmente

Prioridade de aplicação do hardening e dicas operacionais

  • Não é necessário aplicar tudo a todos os serviços
  • O ponto central é o modelo de ameaça e a gestão de risco; em especial, serviços expostos externamente (httpd, nginx, ssh etc.) devem ser considerados prioritários
  • Também é eficaz aplicar de forma preventiva a comandos customizados e unidades timer (substitutas do cron antigo)
  • Quanto menos complexo o serviço, maior a chance de fazer ajustes finos

Checklist: combinação recomendada de opções de segurança (prioridade inicial de aplicação)

  • ProtectSystem=strict
  • PrivateTmp=yes
  • ProtectHome=yes ou ProtectHome=tmpfs
  • ProtectClock=yes, ProtectKernelLogs=yes, ProtectKernelModules=yes
  • RestrictSUIDGUID=yes
  • UMask=0077
  • LockPersonality=yes
  • RestrictRealtime=yes
  • MemoryDenyWriteExecute=yes
  • DynamicUser=yes ou definir User como um usuário específico diferente de root
  • Os itens acima geralmente podem ser usados em serviços com pouco ou nenhum impacto
  • Para aplicar adicionalmente filtragem de syscalls (SystemCallFilter), é necessário testar em detalhe

Exemplo de configuração do Traefik

  • Um caso de uso em que um serviço Traefik baseado em contêiner é executado com systemd quadlet, com várias opções de segurança aplicadas
    • Uso de ProtectSystem=full, ProtectHome=yes, SystemCallFilter=@system-service @mount @privileged etc.
    • Remoção de privilégios específicos com CapabilityBoundingSet=~CAP_SETUID CAP_SETPCAP
    • Aplicação de restrição de acesso de rede com RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX AF_NETLINK etc.

Conclusão

  • As opções de hardening de segurança do systemd são um recurso prático que vale a pena manter no kit de ferramentas de qualquer administrador de sistemas Unix-like
  • Não devem ser tratadas como solução de segurança perfeita, mas como ferramentas para reduzir riscos, e não há necessidade de aplicar configurações de segurança indiscriminadamente a todos os serviços
  • Especialmente para administradores de ambientes self-hosting, elas podem ajudar muito a elevar o nível de segurança
  • Priorizando a "praticidade acima da perfeição", recomenda-se aplicar essas opções ao menos parcialmente, dentro do que fizer sentido para o trabalho e o ambiente

1 comentários

 
GN⁺ 2025-08-20
Comentários do Hacker News
  • Acho interessante que seja possível implementar hardening automatizado de serviços systemd por meio de profiling com strace
    https://github.com/desbma/shh

    • Encontrei um método bem bom: no exemplo não usaram ProtectSystem=, mas
      com TemporaryFileSystem=/:ro, BindReadOnly=/usr/bin/binary /lib /lib64 /usr/lib usr/lib64
      dá para incluir apenas o binário desejado e os caminhos que se quer ler
      ProtectSystem= no momento não é compatível com esse comportamento
      Veja mais detalhes aqui

    • Acho que essa abordagem pode ser problemática para serviços que precisam de ações extras, como enviar e-mail quando ocorre um erro

  • Em comparação com o post de ontem sobre hardening de systemd, este é muito mais realista e cheio de dicas boas que dá para aplicar imediatamente
    Ontem eu tentei dar exemplos mais práticos nos comentários do outro post, e o texto de hoje organizou muito bem o conteúdo realmente útil, mostrando formas rápidas e fáceis de reforçar isolamento e segurança com systemd
    Acho um excelente artigo
    Deixo também o post de ontem como referência
    https://us.jlcarveth.dev/post/hardening-systemd.md
    https://news.ycombinator.com/item?id=44928504

    • Seria bom corrigirem o problema do certificado do site
      Em alguns navegadores nem dá para acessar por causa do erro de certificado
  • Obrigado por compartilhar
    Se você usar systemd-analyze com a flag --user, dá para verificar a segurança das unidades de usuário do systemd (systemd-analyze --user security)
    Passei a usar mais systemd ao migrar containers para Podman, e essa ferramenta deve ajudar bastante a melhorar a segurança de unidades systemd/serviços de container

  • Os scripts de init antigos eram todos diferentes entre si, então esse tipo de hardening consistente era impossível

    • Claro, também dava para fazer esse tipo de hardening com scripts de init antigos, mas o systemd ajuda a usar bons recursos do kernel de forma fácil, padronizada e consistente
      Entrei relativamente tarde no mundo Linux, então é difícil imaginar um sistema sem systemd, e sistemas sem systemd eram muito incômodos de lidar
      Recentemente descobri a ferramenta unshare, que me permitiu fazer experimentos como remontar todo o /nix como RW sem afetar outros processos
      A usabilidade do systemd é um pouco bruta, mas sinceramente a única alternativa que me vem à cabeça é o Windows
  • Fico me perguntando por que as distribuições Linux não ativam mais desses switches de segurança por padrão
    Imagino se existe alguma desvantagem em fazer um hardening conservador
    Para muitos usuários pode haver configurações demais e complexidade demais

    • Se você mudar as configurações de forma agressiva demais, pode acabar quebrando setups existentes sem querer
      Por exemplo, se fizer hardening no NetworkManager, seria preciso validar individualmente se IPv4 e IPv6 continuam funcionando, se os modos dns=systemd-resolved e dns=default operam corretamente, a integração com ModemManager e rede celular, plugins de openvpn ou cisco anyconnect, hooks do NetworkManager-dispatcher e várias outras partes
      Também existe a questão de quantos mantenedores de distribuições podem realmente ter certeza de até que ponto conseguem mudar os switches dos pacotes que administram sem quebrar mais de 0,01% dos ambientes dos usuários
      Se a distribuição gerencia essas flags, ainda vem junto o custo de lidar com problemas de compatibilidade a cada release upstream; por outro lado, se o upstream define isso, a compatibilidade retroativa acaba forçando um uso muito mais cauteloso

    • Essa pergunta é parecida com “por que as distribuições não usam MAC (SELinux etc.) de forma mais rígida por padrão?”
      Também seria melhor restringir mais coisas como o sshd, mas

      1. custo inicial de desenvolvimento para aplicar
      2. custo de lidar com bug reports que surgem em todo tipo de ambiente de usuário
      3. custo de manutenção contínua acompanhando mudanças da distribuição/upstream
        fazem disso um peso grande para distribuições maiores
        O mesmo vale para SELinux e AppArmor: muitos mantenedores consideram o retorno do investimento baixo
    • Outro grande motivo é a falta de capacidade ou recursos para fazer testes de integração exaustivos, parâmetro por parâmetro, garantindo o funcionamento normal de serviços centrais do sistema
      Conversa relacionada
      https://news.ycombinator.com/item?id=29995566
      O resultado de systemd-analyze security varia entre distribuições
      O desbma/shh gera automaticamente regras por unidade, como SyscallFilter, a partir do que foi coletado com strace, de forma semelhante ao audit2allow do SELinux
      Mas instalar strace em ambiente de produção pode ser controverso
      https://github.com/desbma/shh

    • Também não sei ao certo, mas algumas configurações são relativamente novas, então muitos usuários talvez nem as conheçam
      Nem todo mundo é especialista em systemd, e habilitar essas opções também pode trazer o risco de não funcionar corretamente em versões anteriores do systemd
      Há vários recursos como SELinux e AppArmor, mas muitas distribuições, desenvolvedores e usuários simplesmente não sentem tanta necessidade deles, o que dificulta a aplicação automática

  • Há tantas opções de hardening que acho que seria ótimo existir um repositório com exemplos genéricos de hardening por tipo de serviço
    Muitas vezes os usuários acabam aproveitando scripts de hardening usados em comum, mas aí se descobre, de forma inesperada, que é preciso ampliar permissões para evitar casos excepcionais

    • Ao empacotar para distribuições com pouco suporte upstream, como o nixpkgs,
      o mais útil é olhar como as distribuições mais mainstream fazem o empacotamento e o hardening
      Como esses métodos de hardening costumam ser bem testados, se você quiser exemplos de reforço para coisas como postgresql, vale a pena começar pelos pacotes de Debian, Ubuntu e RHEL
  • Um dos ótimos recursos de segurança oferecidos pelo systemd é o gerenciamento de credenciais
    Com isso, dá para passar credenciais para a aplicação de forma mais segura do que armazenando em variáveis de ambiente ou no sistema de arquivos
    Em ambientes sem Vault etc., por exemplo em projetos pessoais, sempre prefiro esse método
    Até criei um pacote Go para integrar com esse recurso
    credentials no systemd
    pacote credential-go

    • Parece aquela cultura de nodejs ou npm de transformar até duas linhas de código em pacote
      Na prática é só

      dir, err := os.Getenv("CREDENTIALS_DIRECTORY")
      cred, err := os.ReadFile(filepath.Join(dir, "name"))
      

      não é mais complexo nem que left-pad
      Pelo que eu sabia, na comunidade Go era considerado virtude reduzir dependências e evitar abstrações desnecessárias (como chamadas de função)
      Esse tipo de operação simples normalmente era algo que cada um escrevia na hora

    • Fiquei curioso sobre como esse mecanismo de entrega de credenciais impede que credenciais sejam herdadas por processos filhos criados com fork

  • Artigo realmente útil
    Gostei também da lista das opções do systemd e do conselho do tipo “consulte o man e boa sorte”
    O systemd é realmente ótimo, e quero implantá-lo ativamente nos meus servidores

  • Uma dica pequena: a grafia correta no título é systemd
    Não é SystemD, system D nem system d; o certo é systemd
    O motivo é que vem de “system daemon”, então, seguindo a tradição Unix/Linux, o nome termina com d minúsculo

    • Curioso
      Eu costumava ver muita gente escrever systemD, então fico me perguntando por que essa forma ficou tão difundida
  • A dica de debugging de problemas de syscall no systemd é realmente muito útil