Programação Por Equipe DevBras

Capa do artigo: Deploy no token do João: como criar conta de serviço que não depende de ninguém

Deploy no token do João: como criar conta de serviço que não depende de ninguém

Troque tokens pessoais por identidades próprias para CI, servidor e banco, com permissão mínima, dono humano, rotação e um inventário que mostra onde cada uma é usada.

Sexta, 17h40. O pipeline de deploy da loja falha com "Bad credentials". Ninguém mexeu no pipeline. O que mudou foi que o João saiu da empresa na quarta, o TI desativou a conta dele no GitHub, e o token pessoal que o João criou em 2023 para "destravar o deploy rapidinho" morreu junto. O final alternativo é pior: ninguém desativa nada, e o João continua com um token capaz de publicar na produção de uma empresa onde ele não trabalha mais.

A resposta curta: robô não usa credencial de gente. Cada sistema automático (pipeline, aplicação, script de backup) ganha uma identidade própria, com a menor permissão que resolve, um dono humano responsável e um registro de onde ela é usada. Quando uma pessoa entra ou sai, nada automático quebra e nada automático fica com o poder dela.

Por que o token pessoal parece prático e vira problema

Token pessoal é o caminho de menor esforço: a pessoa já tem acesso, gera o token em dois cliques, cola no segredo do CI e o deploy volta. O problema é que esse token herda tudo o que a pessoa pode fazer. Se o João era administrador da organização, o pipeline também virou administrador. Um vazamento do segredo do CI vira acesso de administrador.

Além do excesso de poder, a credencial carrega o ciclo de vida da pessoa. Ela vence quando a pessoa sai, troca de equipe ou perde um acesso. Os registros de auditoria mostram "João publicou" quando quem publicou foi o robô, o que confunde qualquer investigação. E, como o token está "no nome do João", ninguém mais se sente responsável por trocá-lo.

O mesmo padrão aparece fora do GitHub: aplicação conectando no banco com o usuário pessoal do DBA, serviço rodando no Linux como o usuário de quem fez a instalação, script de backup usando a chave SSH do notebook de alguém.

Que tipo de identidade usar em cada lugar

  • Dentro do GitHub Actions, o próprio GitHub entrega um GITHUB_TOKEN temporário por execução, com permissões que você restringe no workflow. Para ações no próprio repositório, ele basta.
  • Para acessar outros repositórios ou a API em nome da organização, prefira um GitHub App instalado na organização, com permissões escolhidas e tokens de curta duração.
  • Para um servidor buscar um repositório específico, uma deploy key: chave SSH ligada a um único repositório, somente leitura por padrão.
  • Para o pipeline falar com nuvem (AWS, Azure, Google Cloud), a federação por OIDC do GitHub Actions troca um token de curta duração por credencial temporária, sem segredo fixo guardado.
  • No servidor e no banco, um usuário de sistema e um usuário de banco por serviço, nunca o de uma pessoa.

Tokens pessoais de granularidade fina, com prazo e repositórios escolhidos, são melhores que os clássicos, mas continuam presos a uma pessoa. Servem para uso pessoal, não para robô.

Como migrar a loja, passo a passo

  1. Faça o inventário. Liste todo segredo do CI, toda variável de ambiente com senha ou token, todo usuário de banco e todo serviço do servidor. Para cada um, anote de quem é a credencial.
  2. Crie uma identidade por uso. Uma para o deploy, outra para a aplicação acessar o banco, outra para o backup. Identidade compartilhada entre usos não pode ser revogada sem derrubar todos.
  3. Dê a permissão mínima. O deploy escreve na pasta do site; a aplicação lê e grava em tabelas; o backup só lê.
  4. Nomeie um dono e um substituto. Pessoas, não "o time". São elas que recebem o aviso de expiração e fazem a troca.
  5. Guarde no cofre, nunca na pasta pessoal de ninguém, nem no repositório.
  6. Troque e revogue a antiga. Só depois de a nova estar funcionando, e sempre nessa ordem.
  7. Prove que funciona. Desative temporariamente a conta pessoal de quem configurou e rode o pipeline.

O workflow sem token pessoal

name: publicar
on:
  push:
    branches: [main]

permissions:
  contents: read

jobs:
  publicar:
    runs-on: ubuntu-latest
    environment: producao
    steps:
      - uses: actions/checkout@v4
      - name: Enviar para o servidor
        env:
          CHAVE_DEPLOY: ${{ secrets.DEPLOY_SSH_KEY }}
          HOST_CONHECIDO: ${{ vars.SSH_KNOWN_HOSTS }}
        run: |
          install -m 700 -d ~/.ssh
          printf '%s\n' "$CHAVE_DEPLOY" > ~/.ssh/deploy
          printf '%s\n' "$HOST_CONHECIDO" > ~/.ssh/known_hosts
          chmod 600 ~/.ssh/deploy
          rsync -az --delete -e "ssh -i ~/.ssh/deploy" ./public/ deploy@loja.exemplo.com.br:/srv/loja/

O bloco permissions limita o GITHUB_TOKEN a leitura do código. O environment: producao permite exigir aprovação e restringir o segredo a esse ambiente. A chave SSH não é de ninguém: foi gerada só para isso, e a parte pública está no usuário deploy do servidor. O known_hosts vem de uma variável para que a conexão confira a identidade do servidor em vez de aceitar qualquer um. Como gerar e instalar a chave está em chave SSH na VM.

No servidor e no banco

# quem publica: precisa de shell e de home para o authorized_keys
sudo useradd --system --create-home --shell /bin/bash deploy
sudo chown -R deploy:deploy /srv/loja

# quem roda a aplicação: sem login interativo
sudo useradd --system --no-create-home --shell /usr/sbin/nologin loja
CREATE USER 'loja_app'@'10.0.0.%' IDENTIFIED BY 'senha-gerada-pelo-cofre';
GRANT SELECT, INSERT, UPDATE, DELETE ON loja.* TO 'loja_app'@'10.0.0.%';

CREATE USER 'loja_backup'@'10.0.0.%' IDENTIFIED BY 'outra-senha-do-cofre';
GRANT SELECT, SHOW VIEW, TRIGGER, LOCK TABLES, EVENT ON loja.* TO 'loja_backup'@'10.0.0.%';

Separar deploy de loja significa que uma falha na aplicação não dá permissão de reescrever o próprio código. No systemd, o serviço roda com User=loja. No banco, a aplicação não consegue apagar tabelas e o backup não consegue alterar dados. No MySQL 8, rode o mysqldump desse usuário com --no-tablespaces; sem isso ele pede o privilégio global PROCESS, que você não precisa dar. As senhas nos exemplos são marcadores: a real é gerada e guardada no cofre, e a aplicação a recebe por variável de ambiente ou arquivo de segredo.

O inventário que salva a próxima troca

Mantenha um registro simples, num lugar que o time consulta, com uma entrada por identidade:

identidade:  deploy-loja (chave SSH, usuário deploy no servidor)
usada em:    GitHub Actions do repo loja, segredo DEPLOY_SSH_KEY
permissão:   escrita em /srv/loja
dono:        Marina (substituto: Carlos)
criada em:   2026-03-02
troca até:   2026-09-02

Sem isso, a rotação vira caça ao tesouro: você troca a senha, e três dias depois descobre um cron esquecido num servidor que parou de fazer backup. A troca em si segue a ordem descrita em rotação que tem dois passos.

Erros comuns

  • Token pessoal no CI. O deploy quebra quando a pessoa sai ou, pior, continua funcionando com o poder dela depois que ela saiu.
  • Uma conta de serviço para tudo. Para revogar o acesso do backup, você derruba também o deploy e a aplicação.
  • Conta de serviço sem dono. O aviso de expiração vai para uma caixa que ninguém lê, e a credencial vence numa sexta à noite.
  • Permissão de administrador "para não dar erro". Qualquer vazamento do segredo vira controle total do repositório ou do banco.
  • Revogar antes de trocar. A identidade nova ainda não foi testada, e a antiga já não funciona.
  • Segredo colado no código "temporariamente". Ele fica no histórico do Git mesmo depois de apagado, como explica token de bot que o Git não pode ver.

Checklist

  • Nenhum segredo do CI pertence a uma conta pessoal.
  • O workflow declara permissions com o mínimo necessário.
  • Cada uso (deploy, aplicação, backup) tem identidade própria.
  • A aplicação roda num usuário de sistema sem login interativo.
  • Usuários de banco têm só os privilégios que o serviço usa.
  • Toda identidade tem dono, substituto e data de troca no inventário.
  • O pipeline foi testado com a conta pessoal de quem o configurou desativada.

Abra agora a lista de segredos do seu CI e, para cada um, responda: se a pessoa que o criou fosse desligada hoje, o deploy de amanhã ainda funcionaria por mérito próprio?

Avalie este artigo

Referência: https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens