Executar serviços com utilizador sem privilégios
Executar um serviço como root transforma uma falha em acesso total ao servidor. Use uma conta dedicada sem privilégios ou o DynamicUser do systemd.
Por que não executar tudo como root
root pode fazer qualquer coisa na máquina: ler todos os ficheiros, alterar qualquer definição e apagar o sistema inteiro. Quando executa um serviço como root, atribui todo esse poder ao serviço. Se o serviço tiver um erro que um atacante consiga explorar, o atacante não obtém apenas o serviço. Obtém root, que corresponde ao servidor inteiro. Executar o serviço com um utilizador sem privilégios limita os danos. Um erro num serviço executado com uma conta limitada dá ao atacante acesso apenas ao que essa conta pode modificar, que deve ser quase nada.
Este é o princípio do menor privilégio: dar a cada componente do sistema exatamente o acesso de que precisa para executar a sua função, e nada mais. É o hábito mais eficaz para limitar o impacto de um comprometimento. Num servidor moderno, aplicá-lo tem um custo praticamente nulo.
Uma conta dedicada por serviço
A abordagem clássica consiste em criar um utilizador de sistema separado para cada serviço. Esse utilizador é proprietário apenas dos ficheiros do respetivo serviço e não pode iniciar sessão. Uma conta de sistema para uma aplicação web pode ser criada assim:
sudo useradd --system --no-create-home --shell /usr/sbin/nologin appsvcCada flag tem uma função. --system cria uma conta de serviço, não uma conta para início de sessão humano. --no-create-home não cria um diretório pessoal, que a conta não necessita. --shell /usr/sbin/nologin impede que a conta abra uma shell, mesmo que um atacante consiga obter as credenciais da conta. A conta existe apenas para ser proprietária de um processo e dos respetivos ficheiros.
Depois, dê a essa conta apenas os ficheiros de que necessita, e nenhum outro:
sudo chown -R appsvc:appsvc /opt/myappAgora o serviço lê e escreve no seu próprio diretório e não tem acesso a outras áreas do disco. Se for comprometido, os ficheiros que o atacante pode alterar ficam limitados a /opt/myapp. A conta continua a poder ler tudo o que tenha permissões de leitura para todos, mas não pode modificar o restante sistema.
Faça o systemd executá-lo com essa conta
Depois de criar a conta, configure o systemd para executar o serviço com ela. No ficheiro da unidade, uma linha é suficiente:
[Service]
ExecStart=/opt/myapp/bin/server
User=appsvc
Group=appsvcUser=appsvc significa que o processo inicia com os privilégios limitados dessa conta, em vez dos privilégios de root. Esta é a forma normal e consolidada de executar uma aplicação no systemd, e vale a pena aplicá-la a todos os serviços para os quais criar uma unidade. A redução de privilégios não ajuda se o systemd estiver a monitorizar o processo errado. Se a unidade continuar a indicar active depois de o daemon terminar silenciosamente, confirme se escolheu o Type= correto para a forma como o processo inicia.
Ou ignore a conta com DynamicUser
O systemd pode ir mais longe e criar um utilizador temporário por si. Esse utilizador existe apenas enquanto o serviço está em execução. Defina DynamicUser=yes e não terá de gerir uma conta:
[Service]
ExecStart=/opt/myapp/bin/server
DynamicUser=yes
StateDirectory=myappNo arranque, o systemd atribui um ID de utilizador não utilizado. Na paragem, liberta-o. O serviço também recebe um /tmp privado, uma vista só de leitura da maior parte do sistema de ficheiros e um diretório de estado com permissões de escrita em /var/lib/myapp, que StateDirectory= cria e disponibiliza ao serviço. Nada semelhante era possível no SysV init, onde a redução de privilégios dependia do que o script de arranque do próprio serviço implementasse. Essa limitação explica em grande parte por que motivo as distribuições mudaram para o systemd. Para um serviço autónomo que precisa apenas do seu próprio diretório de estado, DynamicUser=yes é a forma mais simples de obter um isolamento forte, porque não existe uma conta persistente que um atacante possa visar.
Escrever unidades manualmente é trabalhoso, e configurar corretamente as diretivas de reforço de segurança é a parte mais importante. O gerador do guia de serviços e temporizadores do systemd pode preencher estas opções por si, para que a unidade fique correta à primeira.
Como isto se integra com o restante
O princípio do menor privilégio é uma camada de segurança. Ele funciona em conjunto com as outras camadas, em vez de as substituir. Um firewall com política de negação por padrão controla o que pode chegar ao serviço. Executar o serviço com um utilizador sem privilégios controla o que ele pode fazer se for comprometido. O SSH protegido impede que os atacantes entrem no servidor. Nenhuma destas medidas é suficiente por si só. Em conjunto, garantem que uma falha num serviço não compromete todo o servidor. Alojar um serviço que protege segredos mostra onde estas camadas deixam de atuar: uma conta restrita limita aquilo a que um processo comprometido pode aceder, mas um gestor de palavras-passe autoalojado como o Vaultwarden continua a depender da proteção do respetivo token de administração e ficheiro de cópia de segurança. O isolamento de utilizadores não cobre nenhum dos dois.
Antes de avançar, percorra uma checklist de hardening para todo o servidor e gere uma cópia personalizada para utilizar:
FAQ
Por que não devo executar um serviço como root?
Como root pode fazer qualquer coisa na máquina, um serviço executado como root que seja explorado entrega o servidor inteiro ao atacante, e não apenas o serviço. Executar o serviço como uma conta limitada e sem privilégios restringe os danos ao que essa conta consegue aceder. Reserve root para a administração e execute todos os serviços de longa duração como um utilizador restrito.
Como crio um utilizador que não pode iniciar sessão?
Execute sudo useradd --system --no-create-home --shell /usr/sbin/nologin NAME. A shell nologin significa que a conta não pode abrir uma sessão interativa, mesmo que as suas credenciais sejam roubadas, --system marca-a como uma conta de serviço e --no-create-home não cria um diretório pessoal de que ela não precisa. Atribua-lhe a propriedade apenas dos seus próprios ficheiros com chown.
O que é o systemd DynamicUser?
DynamicUser=yes instrui o systemd a criar um utilizador temporário para o serviço, existente apenas enquanto este está em execução. Assim, nunca é necessário gerir uma conta permanente. Também atribui ao serviço um /tmp privado, uma vista do sistema de ficheiros maioritariamente só de leitura e um diretório de estado gerido. É a forma que exige menos esforço para executar um serviço autónomo com uma identidade descartável e com poucos privilégios.
Executar como um utilizador que não seja root substitui uma firewall?
Não. Protegem coisas diferentes. Executar como um utilizador sem privilégios limita o que um serviço pode fazer se for comprometido, enquanto uma firewall limita o que consegue chegar ao serviço. Use ambos, juntamente com SSH reforçado, para que cada camada cubra o que as outras não conseguem.
Que ficheiros devem pertencer ao utilizador do serviço?
Apenas os ficheiros de que o serviço realmente precisa, e nada mais. Atribua à conta a propriedade do seu próprio diretório de trabalho e dos seus dados, e mantenha todo o resto sob propriedade de root. Um padrão adequado é sudo chown -R svc-app:svc-app /opt/svc-app para o diretório da aplicação, enquanto a configuração em /etc permanece sob propriedade de root e só pode ser lida pelo serviço. O objetivo é que, se o processo for comprometido, os ficheiros que ele consegue alterar estejam limitados aos seus próprios dados, e não ao resto do sistema.