# Contas Unix separadas para agentes de programação com IA com segurança

Dar a um agente de programação com IA o seu próprio login Unix é um atalho com consequências duradouras. O agente herda arquivos que você nem lembrava que existiam, credenciais armazenadas por ferramentas anos atrás, uma configuração SSH permissiva, scripts de implantação e a capacidade de fazer uma alteração ruim parecer exatamente com o seu trabalho habitual. Uma conta remota dedicada não torna o agente inofensivo, mas deixa sua autoridade visível e controlável.

Trate a conta como um limite em torno de uma tarefa específica. Se o agente precisa editar um repositório, executar sua suíte de testes e enviar uma branch, crie uma identidade capaz de fazer essas coisas. Não comece com sua conta de desenvolvedor para tentar remover privilégios depois. As permissões Unix se acumulam por meio de grupos, diretórios montados, configurações do shell e ferramentas que presumem que há uma pessoa no controle.

## Uma conta Unix separada dá ao agente uma identidade diferente

Uma conta dedicada dá ao agente um UID distinto, um proprietário de processos, um diretório pessoal, um conjunto próprio de autorizações SSH e um histórico de auditoria. Essas cinco propriedades são mais importantes do que um prompt engenhoso dizendo para o agente permanecer dentro de um repositório.

Quando um agente é executado como `alex`, todo processo que ele inicia pertence a `alex`. Esse processo pode ler tudo o que `alex` consegue ler. Também pode usar o agente SSH de `alex` se o encaminhamento ou os sockets o expuserem. Pode examinar o histórico do shell, as credenciais do Git, a configuração da nuvem, os caches do gerenciador de pacotes e os diretórios de projetos pertencentes a `alex` ou legíveis por ele. Mesmo que o agente se comporte perfeitamente hoje, você fez com que as permissões futuras dele dependam de cada conveniência adicionada à sua própria conta.

Uma conta como `agentbuild` torna o ponto de partida verificável:

```sh
id agentbuild
getent passwd agentbuild
sudo -u agentbuild sh -lc 'umask; pwd; env | sort'
```

Em um host Linux típico, o primeiro comando deve mostrar um UID e uma lista pequena de grupos. O segundo deve mostrar um diretório pessoal como `/srv/agentbuild` ou `/home/agentbuild`, não o diretório pessoal de uma pessoa desenvolvedora. O último comando detecta um problema fácil de ignorar: variáveis de ambiente herdadas podem apontar para arquivos de credenciais, proxies, caches de tokens ou caminhos incomuns de executáveis.

Essa diferença costuma ser confundida: uma chave SSH separada não é uma conta separada. Uma nova chave que entra na sua conta existente só muda a autenticação. Ela não reduz os arquivos, comandos ou configurações de rede disponíveis depois do login. Autenticação separada e autorização separada resolvem problemas diferentes.

Use uma conta estável para uma função estável. Se um agente cria pull requests e outro implanta artefatos de release, dê a eles identidades diferentes. Assim, você poderá responder sem adivinhações a uma pergunta operacional desconfortável: qual conta alterou este arquivo, abriu esta conexão de rede ou criou este processo?

## O limite da conta não contém todos os tipos de dano

Uma conta Unix limita o acesso controlado por propriedade Unix, grupos, listas de controle de acesso e permissões. Ela não limita automaticamente os destinos de rede, o uso de CPU, o esgotamento do disco, vulnerabilidades do kernel, arquivos legíveis por qualquer usuário nem o acesso concedido por uma credencial de serviço compartilhada.

Esse limite ainda vale a pena. Um agente de programação costuma ter capacidade suficiente para alterar o código-fonte, executar scripts de pacotes, ler configurações e usar o Git. Scripts de pacotes podem executar comandos arbitrários do shell. Sistemas de build podem ler variáveis de ambiente. Uma dependência comprometida pode fazer o mesmo. Presuma que qualquer código que o agente peça ao host para executar receberá as permissões da conta que o executa.

Não confunda separação de contas com um contêiner, uma máquina virtual ou um firewall de rede. Cada um tem uma função diferente:

- Uma conta Unix separa arquivos locais, propriedade dos processos e permissões comuns de comandos.
- Um contêiner pode restringir as visões do sistema de arquivos e o uso de recursos, mas uma montagem mal configurada de um diretório do host elimina esse benefício.
- Uma máquina virtual oferece um limite mais forte no sistema operacional quando a carga de trabalho exige isso.
- Os controles de rede decidem a quais destinos a conta pode se conectar e o que pode sair do host.

Escolha a combinação menor que corresponda às consequências de uma falha. Para um checkout de testes descartável, uma conta dedicada em um worker isolado pode bastar. Para um host de implantação em produção, use o limite da conta com SSH restrito, credenciais de implantação específicas, logs e uma política de saída. Se o agente pode alcançar bancos de dados de produção ou material de assinatura, um UID separado claramente não é suficiente.

Uma recomendação popular, mas errada, diz para criar uma conta e adicioná-la aos mesmos grupos operacionais do desenvolvedor «para os builds funcionarem». Isso recria o problema original com outro nome de usuário. Grupos como `docker`, `libvirt`, grupos de backup, grupos de dispositivos e grupos privilegiados de logs podem carregar uma autoridade muito maior do que seus nomes sugerem. Em muitos sistemas, pertencer ao grupo `docker` permite controlar efetivamente o host, pois um membro pode iniciar um contêiner com o sistema de arquivos do host montado.

## Crie uma conta sem heranças acidentais

Crie a conta remota sem login por senha, sem grupo de administradores e com um diretório pessoal que contenha apenas os arquivos colocados ali de propósito. Comece com um diretório vazio, porque dotfiles copiados são uma fonte comum de autoridade acidental.

Os comandos exatos variam conforme o sistema operacional. Em um host no estilo Debian ou Ubuntu, um administrador pode criar uma conta local com um diretório pessoal dedicado assim:

```sh
sudo adduser --disabled-password --gecos '' --home /srv/agentbuild agentbuild
sudo passwd -l agentbuild
sudo install -d -m 700 -o agentbuild -g agentbuild /srv/agentbuild/.ssh
sudo -u agentbuild touch /srv/agentbuild/.hushlogin
```

`--disabled-password` impede a autenticação normal por senha para a nova conta. `passwd -l` torna essa intenção explícita nos sistemas que aceitam o bloqueio de senha. Não trate nenhuma dessas configurações como seu único controle de SSH: o servidor SSH tem suas próprias configurações de autenticação por senha, e uma chave existente ainda pode autenticar se você instalar uma.

Em sistemas com `useradd`, use opções que criem o diretório pessoal e um grupo privado. Depois, confira o resultado em vez de confiar na memória. O gerenciamento de contas em BSD e macOS usa ferramentas diferentes. Consulte o `dscl`, o `sysadminctl` ou o manual de administração do sistema local, em vez de colar comandos Linux em outro host.

Confira a propriedade imediatamente:

```sh
namei -l /srv/agentbuild/.ssh
sudo -u agentbuild sh -lc 'touch ~/permission-test && ls -ln ~/permission-test'
sudo rm /srv/agentbuild/permission-test
```

A saída do `namei` percorre cada componente do caminho. Nenhum diretório pai deve conceder acesso de escrita a um grupo sem relação com a conta, pois isso pode permitir que alguém substitua o diretório `.ssh` ou manipule os arquivos dentro dele. O arquivo de teste deve mostrar o UID numérico e o GID primário da conta.

Não copie seu `.bashrc`, `.zshrc`, `.gitconfig` ou diretório do editor para esse diretório pessoal «para economizar tempo». Esses arquivos costumam adicionar registros privados de pacotes, aliases auxiliares, configurações SSH, gerenciadores de credenciais e hooks do shell. Adicione configurações individuais depois de conseguir explicar por que o agente precisa delas. Um shell simples e não interativo deve ser o padrão para automação remota de qualquer forma.

Defina uma máscara conservadora de criação no ambiente de execução do agente. Um `umask` de `077` mantém novos arquivos regulares privados para a conta, a menos que um comando escolha explicitamente permissões diferentes. Isso às vezes revelará uma suposição do build. Ótimo. Corrija deliberadamente o ponto de compartilhamento do build, em vez de tornar todos os arquivos gerados legíveis por todos os usuários locais.

## Repositórios compartilhados precisam de uma regra de propriedade planejada

O agente deve trabalhar em um checkout que pertença a ele ou em um diretório de projeto cuja propriedade e permissões você consiga explicar. Um diretório em que desenvolvedores, ferramentas de implantação e agentes escrevem como usuários sem relação entre si se torna impossível de entender depois da primeira correção de permissões feita às pressas.

O padrão mais limpo é um checkout pertencente inteiramente à conta do agente. Uma pessoa pode revisar as alterações pelo controle de versão ou ler os arquivos por meio de acesso controlado a um grupo. Isso elimina a maior parte da confusão da colaboração local, e o Git fornece o mecanismo de transferência que realmente importa.

Às vezes o agente precisa escrever em uma árvore de build comum. Nesse caso, crie um grupo de projeto dedicado e defina o bit de ID do grupo no diretório compartilhado, para que novos arquivos herdem o grupo:

```sh
sudo groupadd projectbuild
sudo usermod -aG projectbuild agentbuild
sudo install -d -m 2770 -o releasebot -g projectbuild /srv/project-build
sudo setfacl -m u:agentbuild:rwx /srv/project-build
sudo setfacl -d -m g:projectbuild:rwx /srv/project-build
```

Este exemplo precisa ser ajustado ao seu modelo de propriedade. O ponto não é que listas de controle de acesso estejam na moda. O ponto é nomear a área de colaboração e limitar o acesso de escrita a ela. Não responda a um erro de permissão executando `chmod -R 777` ou mudando uma árvore inteira de código-fonte para um grupo compartilhado de administradores. As duas abordagens escondem o problema até que alguém escreva onde não deveria.

Uma falha sutil aparece quando um diretório de build contém links simbólicos. O agente pode ter permissão de escrita em `/srv/project-build`, enquanto um link dentro dele aponta para `/etc`, para um diretório de release ou para o diretório pessoal de alguém. Examine os scripts de configuração e os diretórios gerados antes de conceder acesso recursivo amplo. O limite da conta só protege os caminhos que o sistema de arquivos realmente avalia com as permissões dessa conta.

O Git tem uma verificação de propriedade relacionada. O Git moderno pode rejeitar um repositório que pareça pertencer a outro usuário, classificando-o como «propriedade duvidosa». Não resolva isso adicionando diretórios arbitrários às configurações globais de `safe.directory` do agente. Faça o checkout pertencer à conta que executa o Git. Se um checkout compartilhado for inevitável, documente sua propriedade e adicione apenas aquele caminho específico depois de entender por que o Git o rejeitou.

## O acesso SSH deve identificar o controlador e limitar a sessão

Use uma chave pública SSH dedicada para o controlador do agente. Quando o fluxo permitir, vincule as restrições a essa chave em `authorized_keys`. Uma conta separada com um shell interativo irrestrito é melhor do que compartilhar o login de uma pessoa desenvolvedora, mas ainda oferece a um processo autônomo uma superfície ampla de comandos.

O OpenSSH documenta os controles disponíveis em `sshd_config(5)` e `authorized_keys`. `PasswordAuthentication no` desativa logins por senha no nível do servidor. `AllowUsers` pode limitar quem consegue entrar. Opções por chave podem desativar encaminhamento de portas, encaminhamento do agente, encaminhamento X11 e alocação de terminal pseudo. São controles comuns, não uma configuração SSH exótica.

Para um agente que só precisa receber um comando Git ou executar um wrapper fixo, uma entrada em `authorized_keys` pode ter esta aparência:

```text
restrict,command="/usr/local/libexec/agent-git-wrapper" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... agent-controller
```

A opção `restrict` é uma abreviação do OpenSSH que desativa vários recursos de encaminhamento e sessão, dependendo da versão do servidor e da página do manual. O `command` forçado faz o servidor executar o wrapper em vez de aceitar o comando solicitado pelo cliente. Teste a versão do OpenSSH instalada antes de depender de uma opção, pois hosts mais antigos podem não oferecer todas as restrições.

O wrapper precisa validar as próprias entradas. Um comando forçado não transforma um script descuidado em um limite de segurança. Se ele passar um comando fornecido pelo cliente, sem aspas, para `sh -c`, o cliente muitas vezes poderá recuperar a execução de comandos. Mantenha o wrapper pequeno, use caminhos fixos, rejeite argumentos inesperados e registre a solicitação.

Para um agente de programação geral que precisa de um shell para inspecionar, editar, compilar e testar, comandos forçados podem ser restritivos demais. Mantenha a chave e a conta dedicadas, desative os encaminhamentos de que não precisa e limite os endereços de origem quando a topologia da rede permitir. A conta remota nunca deve aceitar sua chave SSH pessoal apenas porque ela já está no seu laptop.

Examine a configuração SSH efetiva, não apenas o arquivo que você editou:

```sh
sudo sshd -T | grep -E 'passwordauthentication|permitrootlogin|allowusers|allowgroups'
ssh -vvv agentbuild@build-host true
```

O primeiro comando mostra as configurações efetivas do servidor. O segundo expõe o caminho de autenticação e os métodos rejeitados no lado do cliente. Teste com a chave real do agente. Testar com sua própria chave prova muito pouco.

## As regras de sudo geralmente anulam a proteção que você acabou de criar

Não conceda sudo irrestrito a uma conta de agente. `agentbuild ALL=(ALL) NOPASSWD: ALL` torna o UID separado quase decorativo, pois qualquer comando ou script executado pelo agente pode se tornar root.

As pessoas adicionam essa regra quando um build precisa de uma ação privilegiada e a deixam no lugar porque o build finalmente passou. É assim que uma exceção estreita vira controle permanente do host. Se uma tarefa realmente precisa de elevação, pergunte primeiro se um serviço pertencente ao root, um worker de implantação ou uma ação administrativa separada deveria executá-la.

O manual `sudoers(5)` alerta que a correspondência de comandos tem limitações. Os argumentos importam. Curingas podem corresponder a mais coisas do que os administradores esperam. Permitir um editor, um interpretador, um gerenciador de pacotes, um script de shell gravável pelo agente ou um comando que carregue configurações de um diretório gravável pode levar diretamente à execução arbitrária como root.

Um padrão mais seguro usa um wrapper pertencente ao root com comportamento fixo. Suponha que um agente precise reiniciar um serviço conhecido depois de colocar um artefato já revisado em um diretório fixo. O wrapper deve usar caminhos absolutos para os comandos, rejeitar argumentos, verificar a propriedade e as permissões das entradas e executar apenas esse reinício. Então a regra sudo nomeia exatamente esse wrapper:

```text
Cmnd_Alias AGENT_RELEASE = /usr/local/sbin/restart-project-service
agentbuild ALL=(root) NOPASSWD: AGENT_RELEASE
```

Coloque a regra em um arquivo gerenciado com `visudo` e faça com que o wrapper e seu diretório pai pertençam ao root e não possam ser gravados por `agentbuild`. Isso não garante segurança. Torna verificável a afirmação estreita de que a conta pode executar um único programa pertencente ao root, sem uma string de comando controlada pelo chamador.

Se você não consegue descrever a ação privilegiada permitida em uma frase, ainda não conceda sudo. Divida o trabalho até conseguir. O incômodo é um sinal de projeto, não um motivo para colar uma regra ampla.

## As credenciais precisam de um limite próprio, separado da conta de login

Uma conta restrita ainda se torna perigosa se seu diretório pessoal contiver um arquivo de credencial de nuvem, um token amplo de implantação ou uma chave privada SSH que alcance todos os hosts. Não mova seu conjunto de credenciais do diretório pessoal para o diretório do agente e considere o trabalho concluído.

Emita credenciais para a ação, o escopo e o ambiente de que o agente realmente precisa. Uma credencial de controle de código que pode enviar alterações para um repositório é diferente de uma credencial de registro de produção. Uma chave de implantação limitada a um host é diferente de uma chave privada aceita em toda a infraestrutura. Mantenha essas diferenças visíveis nos nomes das contas, nos comentários e nos registros de revogação.

Evite segredos de longa duração em variáveis de ambiente do shell. Variáveis de ambiente vazam facilmente por meio de saídas de diagnóstico, processos filhos, relatórios de falhas e regras de inspeção de processos que variam conforme o sistema operacional. Às vezes elas são inevitáveis, mas merecem uma vida útil curta e um caminho de inicialização rigorosamente controlado.

O Sallyport mantém as credenciais HTTP e SSH em seu cofre criptografado e executa a ação solicitada sem entregar o texto aberto da credencial a um agente compatível com MCP. Isso é útil quando o agente precisa fazer uma chamada autenticada, mas não deve receber um arquivo de token ou uma chave privada em sua conta remota.

Isso cria duas verificações independentes. A conta Unix remota determina o que o processo pode fazer naquela máquina. O gateway de ações determina se um processo do agente pode solicitar uma credencial que autorize uma ação HTTP ou SSH. Não transforme esses controles em um só: um gateway de credenciais não corrige uma conta remota capaz de ler arquivos de produção, e uma conta limitada não impede um agente de usar um token que recebeu.

Para automação SSH, evite copiar sua chave privada pessoal para `/srv/agentbuild/.ssh`. Crie uma credencial dedicada e restrinja o servidor que a aceita. Se o destino remoto oferecer comandos forçados ou restrições por origem, use-os. Caso contrário, limite a conta nesse destino. A revogação deve significar remover uma credencial de agente, não trocar a chave usada na administração normal.

## Os logs precisam permitir distinguir intenção de execução

Registre a sessão do agente, os comandos da conta quando for viável e as alterações realizadas. Logs que apenas dizem `agentbuild logged in` não ajudarão a reconstruir se uma pessoa solicitou uma ação, se um agente a propôs ou se um script remoto a executou.

O Unix já oferece evidências úteis. Os logs de autenticação SSH identificam a chave aceita e o endereço de origem. A contabilidade de processos ou os recursos de auditoria podem acompanhar a execução, dependendo do host. Os registros de controle de versão mostram commits e arquivos alterados. Os logs de build registram comandos e artefatos. Mantenha os horários sincronizados para poder comparar esses registros.

Não dependa apenas do histórico do shell. Comandos não interativos podem não entrar no histórico, usuários podem editá-lo e um agente pode executar ferramentas que criam seus próprios comandos. O histórico do shell é conveniente para depuração, não um registro confiável.

Uma revisão útil faz quatro perguntas concretas depois de uma execução:

1. Qual controlador se autenticou como a conta do agente?
2. Quais comandos ou jobs de build foram executados com esse UID?
3. Quais arquivos fora do workspace pretendido foram alterados?
4. Com quais sistemas remotos e serviços autenticados o processo entrou em contato?

A resposta à terceira pergunta detecta cedo o crescimento indevido das permissões. Compare os caminhos graváveis pela conta com o workspace pretendido antes que um incidente force esse inventário. Uma lista de processos também pode revelar surpresas: se um agente de build supostamente curto deixa workers em segundo plano, esses workers mantêm as permissões da conta depois que a sessão de orquestração termina.

O Sallyport registra sessões de agentes e ações individuais em um log de auditoria criptografado e encadeado por hashes. `sp audit verify` pode verificar a cadeia offline sem uma chave do cofre. Esse registro é mais forte quando você também preserva as evidências do host remoto, que mostram o que a ação SSH autorizada fez depois de chegar ao destino.

## Um login compartilhado de desenvolvedor falha de maneiras previsíveis

O padrão de falha geralmente começa com um pedido sensato: permitir que o agente execute os mesmos testes que você executa. A pessoa desenvolvedora aponta o agente para um host remoto existente e autoriza sua chave SSH normal, porque o checkout, os caches de pacotes e as dependências do build já funcionam.

O agente executa um comando de teste. A inicialização do teste lê o ambiente da pessoa desenvolvedora e encontra um token de registro. A instalação de uma dependência executa um script de pós-instalação. Esse script pode ler o diretório pessoal da pessoa desenvolvedora, examinar a configuração SSH, usar qualquer auxiliar de credenciais acessível e se conectar usando o alcance de rede já existente para aquele login. Ninguém precisa explorar uma falha do kernel. O processo simplesmente tem a mesma autoridade da pessoa desenvolvedora.

Mais tarde, um script de implantação falha porque espera um caminho de artefatos gravável. Alguém o corrige com uma alteração ampla de grupo. Agora a conta pode escrever em um diretório de release. Uma segunda correção adiciona sudo sem senha porque o reinício de um serviço está bloqueado. A essa altura, a configuração supostamente criada para o agente herdou uma identidade de desenvolvedor, amplo acesso de escrita ao sistema de arquivos, credenciais reutilizáveis e elevação para root.

Uma conta dedicada muda o caminho dessa falha. O teste inicial pode falhar porque a conta não consegue ler uma configuração de registro nem escrever em um cache compartilhado antigo. Essa falha é útil. Ela indica que você deve emitir uma credencial de registro restrita, criar um diretório de cache pertencente à conta ou redesenhar o build. Cada correção se torna uma concessão explícita que pode ser revisada.

Espere algum atrito inicial. Se a nova conta funcionar perfeitamente na primeira tentativa contra uma configuração de desenvolvedor madura, examine-a com atenção. Isso pode significar que o host já disponibilizou dados e autoridade demais para todos os usuários locais.

## Teste o limite como o agente e remova o que surpreender

Teste a conta a partir de uma sessão administrativa separada antes de permitir trabalho sem supervisão. Não faça o teste apenas trocando o prompt do shell e presumindo que a identidade mudou corretamente. Autentique-se com a chave dedicada, use o comando de inicialização real e observe o resultado de fora da sessão.

Execute esta verificação compacta de aceitação depois de cada alteração relevante de acesso:

```sh
ssh -i ./agentbuild_key agentbuild@build-host 'id; umask; pwd; find ~ -maxdepth 1 -printf "%M %u %g %p\n"'
ssh -i ./agentbuild_key agentbuild@build-host 'sudo -n true; echo sudo_status=$?'
ssh -i ./agentbuild_key agentbuild@build-host 'find /srv/project-build -xdev -type f -perm -0002 -print'
```

A primeira linha confirma a identidade, o diretório de trabalho, a máscara de criação e as permissões do diretório pessoal. A segunda normalmente deve retornar um status diferente de zero, pois a conta não deve ter sudo geral. A terceira procura arquivos regulares graváveis por qualquer usuário no diretório de projeto compartilhado. Em sistemas cujo `find` não oferece o `-printf` do GNU, use `ls -ld` e `stat`.

Depois, teste de propósito as ações negadas. Tente ler o diretório pessoal de uma pessoa, escrever fora do workspace, usar o caminho de uma chave de implantação pessoal e abrir uma sessão de encaminhamento SSH caso o encaminhamento deva estar desativado. Uma restrição que nunca foi testada é apenas uma intenção escrita na configuração.

Revise a conta também depois de jobs reais. Remova chaves autorizadas antigas, associações a grupos, caches, listas de controle de acesso temporárias e permissões de implantação quando a tarefa deixar de precisar deles. A limpeza de permissões raramente acontece durante um prazo apertado. Inclua-a nos critérios de conclusão do job.

Comece criando a conta sem acesso além do próprio diretório pessoal e de um checkout de teste. Adicione uma capacidade apenas quando um comando real falhar e você conseguir declarar exatamente a permissão necessária. Essa abordagem parece mais lenta durante a configuração. É muito mais rápida do que tentar descobrir quais partes de um login de desenvolvedor um processo autônomo copiou, usou ou danificou.
