Como manter chaves de API fora dos agentes de IA
Agentes podem vazar chaves de API em uma única chamada de ferramenta. Use tokens com escopo e curta duração atrás de um gateway de credenciais, nunca as chaves reais.
O que significa manter segredos fora dos agentes de IA
Um agente de IA é um processo Linux comum que executa comandos. Todas as variáveis de ambiente mantidas por esse processo podem ser lidas pelo código que ele executa. Portanto, uma chave de API no ambiente do agente é uma chave que o agente pode enviar para qualquer host que consiga alcançar. Manter os segredos fora do agente significa fornecer um identificador em vez da chave: um token com escopo e curta duração ou um marcador que outro componente substitui pelo valor real no limite da rede.
Isso não é uma história sobre um modelo se tornar hostil. O mecanismo é mais simples. Um agente lê uma página da Web, um README ou um comentário de issue que contém instruções e as segue, porque, para um modelo de linguagem, não há diferença entre o texto que você escreveu e o texto que ele obteve. Isso é prompt injection. Depois que isso acontece, o dano é limitado por exatamente uma coisa: o que o processo consegue ler. Se você ainda não definiu um limite, executar um agente de programação com segurança em um servidor apresenta os níveis de isolamento nos quais este guia se baseia.
O modelo de ameaça em termos simples
Execute isto como o usuário que executa seu agente.
tr '\0' '\n' < /proc/self/environ | grep -iE 'key|token|secret|password'Cada linha exibida por ele corresponde a uma solicitação HTTP até o servidor de um desconhecido. Agora observe o que existe no disco próximo ao agente.
grep -rIl --exclude-dir=.git -e 'API_KEY' -e 'SECRET' ~/projects
find ~ -maxdepth 3 -name '.env' -o -name 'credentials' -o -name '*.pem'Um agente com um shell não precisa de uma exploração sofisticada para retirar esses dados. Quatro caminhos comuns são suficientes, e todos parecem trabalho normal no log:
- Um
curloufetchde saída para qualquer host, com o valor em uma cadeia de consulta. - Um
git commitegit pushpara um repositório no qual o agente pode gravar. - Um script de instalação de pacote, que executa código arbitrário como o usuário do agente.
- Uma consulta DNS a um nome de host que contenha o valor, que ainda funciona quando a saída HTTP está bloqueada.
Não é possível resolver isso apenas com revisão. A correção é garantir que não haja nada valioso ao alcance.
Um segredo na árvore de trabalho é um segredo na janela de contexto
Um agente lê arquivos. Um arquivo .env no repositório em que ele está trabalhando será lido. Depois de lido, ele estará na janela de contexto. Isso significa que estará na transcrição, em qualquer log que você mantenha e em tudo o que o agente escrever em seguida.
Antes, com a chave na árvore em que o agente trabalha:
cd ~/projects/billing
cat .env
# STRIPE_SECRET_KEY=sk_live_...
# DATABASE_URL=postgres://app:hunter2@db.internal:5432/billingDepois, com o arquivo fora do alcance:
sudo install -d -m 750 -o root -g agent-review /etc/agent-review
sudo install -m 640 -o root -g agent-review ~/projects/billing/.env /etc/agent-review/billing.env
rm ~/projects/billing/.envO usuário do agente não pode mais abrir o arquivo, porque a árvore de trabalho não o contém mais. As regras de negação na própria configuração do agente são uma segunda camada, não a primeira. O Claude Code lê as regras de permissão de .claude/settings.json no projeto:
{
"permissions": {
"deny": ["Read(./.env)", "Read(./secrets/**)", "Read(./**/*.pem)"]
}
}Isso impede que o agente abra um arquivo por engano durante a exploração. Não impede que uma instrução injetada execute base64 .env, porque esse é um comando do shell, não uma leitura de arquivo. Trate a configuração como uma barreira de proteção e a permissão do sistema de arquivos como a parede. A mesma separação se aplica dentro de containers: arquivos env e segredos no Docker Compose aborda a versão desse problema uma camada abaixo.
Dê a cada agente seu próprio usuário sem privilégios
Se o agente for executado como você, ele herdará suas chaves SSH, suas credenciais de nuvem e seu histórico do shell. Um usuário separado exige um comando e remove tudo isso.
sudo adduser --disabled-password --gecos "" agent-review
sudo chmod 700 /home/agent-review
sudo -u agent-review cat ~/.ssh/id_ed25519A última linha deve falhar com cat: /home/you/.ssh/id_ed25519: Permission denied. Se ela exibir uma chave, seu diretório pessoal pode ser lido pelo grupo ou por qualquer usuário, e chmod 700 ~ corrige isso. Não adicione o usuário do agente a sudo e não forneça a ele uma regra NOPASSWD mais ampla que o único comando de que ele realmente precisa. Usuários com privilégios mínimos em um VPS detalha as configurações de grupo e sudoers.
Também vale a pena adicionar mais um limite em um VPS na nuvem. O serviço de metadados da instância responde em um endereço local de link fixo e frequentemente fornece credenciais de função a qualquer solicitante.
sudo iptables -A OUTPUT -m owner --uid-owner agent-review -d 169.254.169.254 -j REJECTVerifique isso pelo lado do agente. sudo -u agent-review curl -s --max-time 3 http://169.254.169.254/ deve não exibir nada e terminar com um código diferente de zero, porque o pacote é rejeitado antes de sair do host.
Injete a credencial no limite
O padrão que realmente resolve esse problema é a injeção de credenciais. O agente nunca mantém uma chave real. Ele envia a solicitação por um gateway local, e o gateway substitui um marcador secreto pelo segredo real no envio. O segredo fica armazenado no gateway, em um processo diferente, pertencente a outro usuário.
OneCLI é uma implementação de código aberto desse padrão, licenciada sob Apache-2.0, e é executado como um container ao lado do agente. Em julho de 2026, o projeto documenta esta configuração:
git clone https://github.com/onecli/onecli.git
cd onecli
docker compose -f docker/docker-compose.yml up -d --waitO dashboard escuta na porta 10254, e o gateway, na porta 10255. Você armazena a credencial real uma vez e fornece a cada agente um valor de marcador no lugar da chave, além do próprio token de acesso com escopo definido, que ele envia em um cabeçalho Proxy-Authorization. O gateway identifica a solicitação de saída pelo host e pelo caminho, descriptografa a credencial correspondente e a substitui. O ambiente do agente não contém nada que valha a pena roubar.
O valor dessa abordagem não está na criptografia. Está no fato de que a pergunta "o que este agente usou e quando" se transforma em uma consulta ao log. Você consulta uma única trilha de auditoria, em vez de tentar descobrir em qual das seis variáveis de ambiente havia uma cópia da chave.
Passe o segredo ao processo, não ao ambiente
Se você executar o agente com systemd, não precisará de variáveis de ambiente. LoadCredential= coloca o segredo em um diretório privado que somente esse serviço pode ler, exposto como %d no arquivo da unidade e como $CREDENTIALS_DIRECTORY dentro do processo. O valor nunca aparece em /proc/<pid>/environ, portanto ps eww não pode exibi-lo, e o diretório desaparece quando o serviço é interrompido.
Criptografe primeiro a credencial para a máquina. Estes comandos vêm da documentação do systemd e funcionam no systemd 250 ou mais recente, que inclui Ubuntu 24.04 e Debian 13:
echo -n 'sk-example-value' > /tmp/plain.txt
sudo systemd-creds encrypt --name=api_key /tmp/plain.txt /etc/credstore/api_key.cred
shred -u /tmp/plain.txt
sudo systemd-run -P --wait -p LoadCredentialEncrypted=api_key:/etc/credstore/api_key.cred \
systemd-creds cat api_keyO último comando exibe sk-example-value. Isso comprova que o arquivo criptografado é descriptografado neste host. Em seguida, faça referência a ele na unidade:
[Service]
User=agent-review
LoadCredentialEncrypted=api_key:/etc/credstore/api_key.cred
Environment=AGENT_KEY_FILE=%d/api_key
ExecStart=/usr/local/bin/agent-workerO código do agente abre o arquivo em $AGENT_KEY_FILE quando precisa do valor. A leitura de um arquivo ocorre em um momento específico. Uma variável de ambiente permanece durante toda a vida útil do processo, em cada processo filho que ele inicia.
Prefira tokens de curta duração a chaves de longa duração
Uma chave que nunca expira continua válida quando aparece, meses depois, em um log ou em uma transcrição. Quando o serviço oferecer um token de sessão, use-o e defina o menor tempo de vida permitido pelo trabalho.
aws sts assume-role \
--role-arn arn:aws:iam::123456789012:role/agent-readonly \
--role-session-name agent-review \
--duration-seconds 900Quinze minutos é o mínimo aceito pelo AWS STS (security token service) e geralmente é suficiente para uma tarefa de um agente. No GitHub, dê ao usuário do agente seu próprio login gh com um token de escopo refinado, limitado ao único repositório em que ele trabalha, para que gh auth token dentro dessa sessão retorne algo que não possa acessar nenhum outro recurso. Primeiro limite por recurso e depois por tempo.
Verifique e continue verificando
Vale a pena executar três verificações após qualquer alteração na configuração de um agente. Execute-as como o usuário do agente, não como você.
sudo -u agent-review env | grep -iE 'key|token|secret'
sudo -u agent-review ls -la /home/you/ 2>&1 | head -3
sudo -u agent-review curl -s -o /dev/null -w '%{http_code}\n' --max-time 5 https://api.github.com/userA primeira não deve exibir nada. A segunda deve exibir ls: cannot open directory '/home/you/': Permission denied. A terceira informa qual identidade o caminho de rede do agente apresenta. Essa é a pergunta que o padrão de gateway existe para responder: 401 significa que o agente não está usando nenhuma credencial própria do GitHub, e 200 significa que está usando uma. Nesse caso, você deve saber qual token está sendo usado. Se você executar agentes sem supervisão, controlar os custos de agentes de IA em um VPS aborda os limites de orçamento que acompanham esses limites de acesso.
FAQ
Posso simplesmente confiar que o modelo não vazará minhas chaves?
Não, porque o modelo não é o invasor neste modelo de ameaça. O agente lê texto de páginas da web, repositórios e sistemas de acompanhamento de issues, e esse texto pode conter instruções. O modelo não tem uma forma confiável de distinguir suas instruções do texto que buscou. Qualquer controle que dependa de o modelo escolher corretamente falha na primeira vez em que uma instrução injetada for convincente. Portanto, o controle precisa estar no sistema operacional ou na rede.
As variáveis de ambiente são realmente tão ruins para os segredos do agente?
Elas são ruins de uma forma específica: são herdadas. Todo processo filho criado pelo agente recebe uma cópia, incluindo um script de compilação, um executor de testes e qualquer hook de instalação de pacotes. As variáveis também podem ser lidas por meio de /proc/<pid>/environ pelo mesmo usuário. Assim, qualquer coisa executada pelo agente pode lê-las sem que o agente as repasse. Um arquivo lido no momento do uso, com LoadCredential= ou um gateway, limita a exposição a esse momento.
Colocar os segredos em um vault resolve o problema sozinho?
Apenas parcialmente. Um vault resolve o armazenamento. Ele não resolve a última etapa, em que algo retira o segredo do vault e o entrega ao agente como uma variável de ambiente. Isso coloca você novamente na situação inicial. O que importa é quem faz a substituição. Se o agente busca o segredo, o agente fica com o segredo. Se um gateway ou o sistema de inicialização faz a substituição fora do processo do agente, o agente nunca mantém o segredo.
Como posso saber se um agente já vazou alguma coisa?
Normalmente, não é possível saber depois do fato. Esse é o motivo para usar o gateway. Sem um gateway, suas evidências ficam espalhadas pelo histórico do shell, pela transcrição do agente e pelos logs de conexões de saída que provavelmente não estão sendo mantidos. Com um gateway de credenciais, cada uso de uma credencial aparece em uma linha com a identidade do agente e um registro de data e hora. Se você suspeitar de um vazamento, faça a rotação da chave primeiro e investigue depois. A rotação é barata, e a certeza não é.
O que devo fazer no mínimo hoje?
Mova todos os arquivos .env para fora dos diretórios em que seus agentes trabalham e crie um usuário sem privilégios para cada agente. Essas duas mudanças levam cerca de dez minutos e fecham o caminho mais comum: um agente ler um arquivo de credenciais que não tinha motivo para ficar junto do código. O gateway e os tokens de curta duração são a próxima etapa, não a primeira. O mesmo ponto de partida se aplica a qualquer runtime de agente, incluindo executar um agente autônomo com segurança em um VPS.