---
title: "A ingenuidade de confiar apenas no usuário sem sudo para conter um processo web"
author: "Pedro Dalben"
date: "2026-10-22T11:03:04Z"
category: "DevOps & Cloud"
reading_time: "7 min"
canonical: "https://pedrodalben.com.br/blog/a-ingenuidade-de-confiar-apenas-no-usuario-sem-sudo-para-conter-um-processo-web"
---

# A ingenuidade de confiar apenas no usuário sem sudo para conter um processo web

> Conter um processo web no Linux exige travar o sistema de arquivos via systemd, porque permissões POSIX padrão não impedem vazamento de dados.

**Autor:** Pedro Dalben (CTO no Integrar Plus)  
**Publicado em:** 22 de October de 2026  
**URL Canônica Oficial:** [https://pedrodalben.com.br/blog/a-ingenuidade-de-confiar-apenas-no-usuario-sem-sudo-para-conter-um-processo-web](https://pedrodalben.com.br/blog/a-ingenuidade-de-confiar-apenas-no-usuario-sem-sudo-para-conter-um-processo-web)  

---


Existe uma divisão clássica entre quem opera servidores próprios. De um lado, estão os defensores da conteinerização irrestrita, que insistem que qualquer serviço rodando direto no sistema operacional é uma falha de segurança e que namespaces só devem ser consumidos via Docker ou Podman. Do outro lado, ficam os minimalistas que criam um usuário local sem privilégios de sudo, colocam o Puma ou o sidekiq para rodar sob essa conta e acreditam que o problema de contenção foi encerrado aí.

Eu discordo das duas posturas. A exigência de rodar containers para qualquer processo em uma VPS adiciona camadas de rede virtual, sistemas de arquivos em camadas e daemons extras para resolver algo que o kernel já faz nativamente. Por outro lado, supor que um usuário comum do Linux sem acesso ao sudo oferece isolamento aceitável é uma ilusão perigosa.

Se a sua aplicação web sofrer uma execução remota de código ou se uma dependência for comprometida, a conta do processo não precisa de root para causar estrago. Um usuário comum consegue ler boa parte da hierarquia do Linux. Ele lê chaves públicas em diretórios home vizinhos se a máscara de criação falhar, vasculha configurações globais em `/etc`, inspeciona argumentos de outros processos em `/proc` e usa diretórios públicos como `/tmp` ou `/var/tmp` para descarregar binários compilados e manter persistência.

O isolamento real em um servidor Linux sem a sobrecarga de containers passa pelo gerenciador de inicialização. O systemd gerencia cgroups e namespaces de montagem no próprio PID 1. Quando você configura uma unit com diretivas de restrição de sistema de arquivos, o kernel monta uma visão customizada da árvore de diretórios exclusiva para aquele processo antes de invocar o executável.

### O buraco aberto nas permissões tradicionais

A maioria dos deploys tradicionais cria um usuário de serviço, como `app`, e coloca o código em `/var/www` ou dentro de `/home/app`. Quem adota esse modelo quase sempre confia que a ausência de permissão de escrita fora do diretório da aplicação protege a máquina.

Isso ignora a superfície de leitura. Uma aplicação Rails carrega dezenas de gems nativas. Se uma dessas bibliotecas for vulnerável a leitura arbitrária de arquivos, o processo tem passe livre para inspecionar arquivos legíveis por qualquer usuário. Em muitas distribuições, diretórios de usuários sob `/home` são criados historicamente com permissão de leitura para terceiros, a menos que alguém tenha tido o cuidado explícito de ajustar o umask ou aplicar chmod 700.

Além disso, áreas compartilhadas de escrita são um convite para execução indireta de código. O `/tmp` padrão tem permissão de escrita irrestrita com sticky bit. Se o processo pode escrever lá, ele pode criar arquivos executáveis, scripts e sockets Unix que interagem com outros serviços da máquina sem que você perceba.

### Fechando o cerco com ProtectHome e ProtectSystem

O primeiro passo para conter o processo é retirar a visão dos dados de usuários humanos da máquina. O systemd resolve isso com uma única diretiva chamada `ProtectHome`.

Ao declarar `ProtectHome=true`, os diretórios `/home`, `/root` e `/run/user` ficam totalmente inacessíveis para o processo da aplicação, mapeados como diretórios vazios e sem permissão. Se você quiser um nível mais agressivo, `ProtectHome=strict` transforma esses caminhos em montagens somente leitura. Em servidores onde a aplicação roda sob um usuário dedicado e não precisa de nenhum arquivo pessoal de administradores, essa diretiva elimina o risco de um processo comprometido extrair chaves SSH ou históricos de shell de quem mantém o servidor.

Em seguida vem o sistema operacional como um todo. A diretiva `ProtectSystem` cuida das pastas que compõem a base do Linux:

```ini
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
```

O valor `strict` monta praticamente toda a hierarquia do sistema de arquivos, incluindo `/usr`, `/boot`, `/etc` e até `/var`, em modo somente leitura para a unit. Isso quebra a premissa de qualquer script malicioso que tente alterar bibliotecas compartilhadas, injetar arquivos de configuração ou tocar em binários do sistema.

A diretiva `PrivateTmp=true` complementa essa barreira criando um namespace de arquivos temporários isolado. O `/tmp` e o `/var/tmp` que a sua aplicação enxerga são exclusivos dela, invisíveis para o resto do sistema operacional e descartados automaticamente quando a unit para.

### Liberando apenas o necessário com ReadWritePaths

Quando você aplica `ProtectSystem=strict`, a aplicação para de funcionar imediatamente se tentar escrever logs, arquivos temporários de compilação de assets, uploads locais ou sockets de conexão. Essa quebra é esperada e desejável. Ela obriga você a declarar formalmente onde o processo tem autorização explícita para gravar dados.

É aqui que entra o `ReadWritePaths`. Em vez de deixar o sistema inteiro aberto e tentar bloquear caminhos específicos, você bloqueia tudo na base e abre exceções pontuais:

```ini
[Unit]
Description=Aplicacao Web Rails Puma
After=network.target

[Service]
Type=simple
User=app
Group=app
WorkingDirectory=/srv/app/current

## Isolamento de filesystem
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true

## Pastas permitidas para gravacao
ReadWritePaths=/srv/app/current/log /srv/app/shared/storage /srv/app/current/tmp

## Protecoes complementares de processo
NoNewPrivileges=true
ProtectKernelTunables=true
ProtectControlGroups=true
RestrictRealtime=true

ExecStart=/srv/app/current/bin/puma -C /srv/app/current/config/puma.rb
Restart=always

[Install]
WantedBy=multi-user.target
```

Nessa configuração, mesmo que a aplicação sofra um ataque que permita gravação arbitrária de arquivos, ela não conseguirá tocar em nada fora dos três caminhos declarados em `ReadWritePaths`. O `/etc` é somente leitura, o `/usr` é somente leitura e os diretórios de outros usuários sequer existem na árvore visível pelo processo.

A diretiva `NoNewPrivileges=true` impede que o binário ou qualquer processo filho ganhe privilégios adicionais por meio de binários setuid ou capacidades especiais do kernel. Se alguém tentar executar um binário que normalmente elevaria privilégios na máquina, o kernel bloqueia a transição.

### O custo operacional e onde o modelo exige atenção

Existe uma fricção real ao adotar esse nível de contenção. Atualizações de aplicação, criação de novas pastas de cache ou mudanças na arquitetura de logs exigem atualizar o arquivo de unit do systemd e recarregar a configuração com `systemctl daemon-reload`.

Outro ponto que exige cuidado é a inicialização de ferramentas que precisam ler configurações locais. Se a sua aplicação invoca utilitários do sistema que dependem de arquivos dentro de `/etc` que não foram liberados ou se uma gem tenta verificar variáveis de hardware em `/sys`, você precisará inspecionar as falhas pelo `journalctl` e adicionar diretivas como `ReadOnlyPaths` ou relaxar proteções pontuais.

Eu costumo testar essas restrições primeiro em um ambiente de homologação idêntico à produção, monitorando os erros de permissão do kernel no log do sistema antes de travar o serviço principal. A complexidade de manter essa dúzia de linhas no arquivo de unit é muito menor do que a manutenção de uma pilha inteira de orquestração de containers, entregando uma contenção que opera diretamente nas primitivas de segurança do kernel Linux.
