Reforço de segurança (hardening) de serviços systemd
(roguesecurity.dev)- 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.confe afins - Entre as principais opções estão
ProtectSystem,PrivateTmp,NoNewPrivileges,SystemCallFilter,MemoryDenyWriteExecutee 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.servicepara 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 7e afins - Algumas opções representativas relacionadas à segurança
ProtectSystem→ opção para restringir o sistema de arquivos a somente leituraProtectHome→ opção para bloquear acesso a/home,/root,/run/userPrivateDevices→ opção para bloquear acesso a dispositivos físicos e permitir apenas dispositivos virtuais como/dev/nullProtectKernelTunables,ProtectKernelModules,ProtectKernelLogs→ opções para bloquear acesso a recursos do kernelNoNewPrivileges→ 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 JITSystemCallFilter→ 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,/sysexigem 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,/syscomo 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
/procconteú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-filterouman systemd.exec(5) - É possível negar toda a lista com o prefixo
~(ex.:CapabilityBoundingSet=~CAP_SETUIDetc.)
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 recente verifique o valor da syscall - Em seguida, adicione essa syscall ou um grupo relacionado em
SystemCallFilterpara resolver o problema gradualmente
- Execute
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=strictPrivateTmp=yesProtectHome=yesouProtectHome=tmpfsProtectClock=yes,ProtectKernelLogs=yes,ProtectKernelModules=yesRestrictSUIDGUID=yesUMask=0077LockPersonality=yesRestrictRealtime=yesMemoryDenyWriteExecute=yesDynamicUser=yesou definirUsercomo 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 @privilegedetc. - 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_NETLINKetc.
- Uso de
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
Comentários do Hacker News
Acho interessante que seja possível implementar hardening automatizado de serviços systemd por meio de profiling com
stracehttps://github.com/desbma/shh
Encontrei um método bem bom: no exemplo não usaram
ProtectSystem=, mascom
TemporaryFileSystem=/:ro, BindReadOnly=/usr/bin/binary /lib /lib64 /usr/lib usr/lib64dá para incluir apenas o binário desejado e os caminhos que se quer ler
ProtectSystem=no momento não é compatível com esse comportamentoVeja 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
Em alguns navegadores nem dá para acessar por causa do erro de certificado
Obrigado por compartilhar
Se você usar
systemd-analyzecom 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
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/nixcomo RW sem afetar outros processosA 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-resolvededns=defaultoperam corretamente, a integração com ModemManager e rede celular, plugins de openvpn ou cisco anyconnect, hooks do NetworkManager-dispatcher e várias outras partesTambé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, masfazem 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 securityvaria entre distribuiçõesO
desbma/shhgera automaticamente regras por unidade, comoSyscallFilter, a partir do que foi coletado comstrace, de forma semelhante aoaudit2allowdo SELinuxMas instalar
straceem ambiente de produção pode ser controversohttps://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
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 RHELUm 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
nodejsounpmde transformar até duas linhas de código em pacoteNa prática é só
não é mais complexo nem que
left-padPelo 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 é
systemdNão é
SystemD,system Dnemsystem d; o certo ésystemdO motivo é que vem de “system daemon”, então, seguindo a tradição Unix/Linux, o nome termina com
dminúsculoEu costumava ver muita gente escrever
systemD, então fico me perguntando por que essa forma ficou tão difundidaA dica de debugging de problemas de syscall no systemd é realmente muito útil