Como rodar serviços como usuário comum
Evite o risco de comprometimento total do servidor. Aprenda a usar contas de sistema dedicadas ou a flag DynamicUser do systemd para isolar processos.
Por que não rodar tudo como root
O root pode fazer qualquer coisa na máquina: ler todos os arquivos, alterar qualquer configuração, deletar o sistema inteiro. Quando você roda um serviço como root, você entrega todo esse poder ao serviço. Se o serviço tiver um bug que um atacante possa explorar, ele não ganha apenas o serviço, ele ganha o root, e o root é o servidor inteiro. Rodar como um usuário sem privilégios contém o dano. Um bug em um serviço que roda como uma conta limitada dá ao atacante apenas o que essa conta pode tocar, o que deve ser quase nada.
Este é o princípio do privilégio mínimo: dê a cada parte do sistema exatamente o acesso que ela precisa para realizar seu trabalho, e nada mais. É o hábito mais eficaz para limitar o raio de explosão de um comprometimento, e em um servidor moderno o custo para aplicar é quase zero.
Uma conta dedicada por serviço
A abordagem clássica é criar um usuário de sistema separado para cada serviço, um que possua apenas os arquivos daquele serviço e não possa fazer login. Uma conta de sistema para um web app pode ser assim:
sudo useradd --system --no-create-home --shell /usr/sbin/nologin appsvcCada flag é importante. --system torna-o uma conta de serviço, não um login humano. --no-create-home pula um diretório home que ele não precisa. --shell /usr/sbin/nologin significa que, mesmo que um atacante consiga a conta de alguma forma, ele não pode abrir um shell com ela. A conta existe apenas para ser dona de um processo e de seus arquivos.
Então, dê a esse usuário apenas os arquivos que ele precisa, e nada mais:
sudo chown -R appsvc:appsvc /opt/myappAgora o serviço lê e escreve em seu próprio diretório e não tem razão para estar em nenhum outro lugar no disco. Se ele for explorado, os arquivos que o atacante pode alterar limitam-se a /opt/myapp; a conta ainda pode ler qualquer coisa que seja legível por todos (world-readable), mas não pode modificar o resto do sistema.
Deixe o systemd rodar como esse usuário
Assim que a conta existir, instrua o systemd a rodar o serviço como ela. No arquivo de unidade, uma linha faz isso:
[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 do root. Esta é a maneira normal e comum de rodar uma aplicação sob o systemd, e vale a pena fazer isso para cada serviço para o qual você escreva uma unidade.
Ou pule a conta inteiramente com DynamicUser
O systemd pode ir um passo além e criar um usuário temporário para você, um que existe apenas enquanto o serviço está rodando. Defina DynamicUser=yes e você não gerencia conta alguma:
[Service]
ExecStart=/opt/myapp/bin/server
DynamicUser=yes
StateDirectory=myappNo início, o systemd aloca um ID de usuário não utilizado; no término, ele o libera. O serviço também recebe um /tmp privado, uma visão de leitura apenas da maior parte do filesystem, e um diretório de estado gravável sob /var/lib/myapp que o StateDirectory= configura e entrega a ele. Para um serviço autônomo que só precisa de seu próprio diretório de estado, DynamicUser=yes é a forma de menor esforço para obter isolamento forte, pois não existe uma conta de longa duração para um atacante visar.
Escrever unidades manualmente é trabalhoso, e configurar corretamente as diretivas de hardening é onde reside a maior parte do valor. O gerador em o guia de serviço e timer do systemd pode preencher essas opções para você para que a unidade esteja correta de primeira.
Como isso se encaixa com o restante
O privilégio mínimo é uma camada, e ele funciona com as outras em vez de substituí-las. Um firewall de negação padrão controla o que pode alcançar o serviço; rodá-lo como um usuário sem privilégios controla o que o serviço pode fazer se for invadido; e o SSH endurecido mantém atacantes fora da máquina desde o início. Nenhuma dessas camadas sozinha é suficiente, e juntas elas significam que um bug em um serviço não se torna um comprometimento de todo o servidor.
Antes de prosseguir, execute um checklist de hardening para toda a máquina e gere uma cópia personalizada para trabalhar:
FAQ
Por que eu não devo rodar um serviço como root?
Porque o root pode fazer qualquer coisa na máquina; um serviço rodando como root que seja explorado entrega ao atacante o servidor inteiro, não apenas o serviço. Rodar o serviço como uma conta limitada e sem privilégios contém o dano ao que quer que essa conta possa acessar. Reserve o root para administração e rode cada serviço de longa duração como um usuário restrito.
Como eu crio um usuário que não pode fazer login?
Rode sudo useradd --system --no-create-home --shell /usr/sbin/nologin NAME. O shell nologin significa que a conta não pode abrir uma sessão interativa mesmo se suas credenciais forem roubadas, --system marca como uma conta de serviço, e --no-create-home pula um diretório home que ele não precisa. Dê a ele a propriedade apenas de seus próprios arquivos com chown.
O que é o systemd DynamicUser?
DynamicUser=yes diz ao systemd para criar um usuário temporário para o serviço que existe apenas enquanto ele roda, então você nunca gerencia uma conta de longa duração. Isso também dá ao serviço um /tmp privado, uma visão de filesystem majoritariamente de leitura, e um diretório de estado gerenciado. É a forma de menor esforço para rodar um serviço autônomo sob uma identidade temporária de baixos privilégios.
Rodar como um usuário não-root substitui um firewall?
Não. Eles protegem coisas diferentes. Rodar como um usuário sem privilégios limita o que um serviço pode fazer se for invadido, enquanto um firewall limita o que pode alcançar o serviço. Use ambos, junto com SSH endurecido, para que cada camada cubra o que as outras não conseguem.
Quais arquivos o usuário do serviço deve possuir?
Apenas os arquivos que o serviço realmente precisa, e nada mais. Dê à conta a propriedade de seu próprio diretório de trabalho e de seus dados, e deixe todo o resto pertencente ao root. Um bom padrão é sudo chown -R svc-app:svc-app /opt/svc-app para o diretório da aplicação, enquanto a configuração sob /etc permanece pertencente ao root e é apenas legível pelo serviço. O objetivo é que, se o processo for comprometido, os arquivos que ele pode alterar limitem-se aos seus próprios dados, não ao resto do sistema.