Pular para o conteúdo

Deploy na nuvem sem chave de longa duração

Avançado14 min de leituracicd

Ao final deste guia, o seu pipeline faz deploy na nuvem sem nenhuma chave guardada como segredo do repositório. O CI apresenta um token de identidade assinado, a nuvem confia naquele emissor para aquele repositório específico, e devolve uma credencial temporária.

1. Entenda por que a chave estática é o pior segredo

Seção intitulada “1. Entenda por que a chave estática é o pior segredo”

Uma AWS_ACCESS_KEY_ID no repositório tem três propriedades ruins ao mesmo tempo: não expira, funciona de qualquer lugar do mundo, e circula por logs, forks e máquinas de desenvolvimento. Vazou, o atacante tem o mesmo poder que o seu pipeline — pelo tempo que levar até alguém perceber.

Com OIDC, a credencial dura minutos, só existe dentro da execução e é emitida apenas para a identidade que a política aceitou.

Registre o emissor do seu CI uma única vez por conta.

Janela do terminal
# AWS — provedor de identidade do GitHub Actions
aws iam create-open-id-connect-provider \
--url https://token.actions.githubusercontent.com \
--client-id-list sts.amazonaws.com

Para GitLab, o emissor é a URL da sua instância (https://gitlab.com). Para Azure e GCP, o equivalente é federated credential no Entra ID e Workload Identity Pool no IAM.

Este é o passo que a maioria erra, e é o que decide se a configuração protege alguma coisa. Sem a condição de sub, qualquer workflow do GitHub consegue assumir o seu papel.

{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": { "Federated": "arn:aws:iam::000000000000:oidc-provider/token.actions.githubusercontent.com" },
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
"token.actions.githubusercontent.com:sub": "repo:empresa/loja:ref:refs/heads/main"
}
}
}]
}

Use StringEquals sempre que possível. Se precisar de curinga (vários ambientes), prefira StringLike com o prefixo mais específico que funcionar:

repo:empresa/loja:environment:producao ← melhor: preso a um Environment protegido
repo:empresa/loja:ref:refs/tags/v* ← aceitável: só tags de release
repo:empresa/* ← perigoso: qualquer repositório da organização
repo:* ← nunca

Dê ao papel apenas as permissões do deploy — publicar imagem, atualizar o serviço. Não use papel de administrador “por enquanto”.

name: deploy
on:
push: { branches: [main] }
permissions:
id-token: write # sem isto, o token OIDC não é emitido
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
environment: producao # aprovação e proteção do ambiente
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::000000000000:role/deploy-loja-prod
aws-region: sa-east-1
role-session-name: gh-${{ github.run_id }} # rastreável na auditoria
- run: aws sts get-caller-identity # confirme quem você é
- run: aws ecs update-service --cluster loja --service api --force-new-deployment

Nenhum secrets.AWS_* aparece no arquivo. Esse é o resultado esperado.

Janela do terminal
# quem assumiu o papel, e a partir de qual workflow
aws cloudtrail lookup-events --lookup-attributes \
AttributeKey=EventName,AttributeValue=AssumeRoleWithWebIdentity --max-results 20
# chaves estáticas ainda ativas — o objetivo é esta lista ficar vazia
aws iam get-credential-report --output text --query Content | base64 -d | \
awk -F, '$9=="true" {print $1, $10}'

Depois de confirmar dois ou três deploys bem-sucedidos, apague a chave antiga no IAM e remova o segredo do repositório. Enquanto a chave existir, o risco continua igual.

Erro Causa provável
Not authorized to perform sts:AssumeRoleWithWebIdentity O sub da política não bate com o do workflow
Credentials could not be loaded Faltou permissions: id-token: write
Funciona em main e falha em PR O sub do PR é pull_request, não ref:refs/heads/... — e isso é proposital
InvalidIdentityToken Emissor errado, ou aud diferente de sts.amazonaws.com

Para ver o sub real que o seu workflow apresenta, imprima os claims do token em um job temporário e compare com a política — mas remova esse job depois.

  • Provedor OIDC registrado na conta.
  • Política de confiança restrita por repositório e por referência ou ambiente.
  • Papel com permissões mínimas de deploy.
  • Workflow com id-token: write e sem segredo de nuvem.
  • Chave estática antiga apagada no IAM e removida do repositório.
  • Uso visível na trilha de auditoria.