Deploy na nuvem sem chave de longa duração
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.
2. Crie a confiança OIDC no provedor
Seção intitulada “2. Crie a confiança OIDC no provedor”Registre o emissor do seu CI uma única vez por conta.
# AWS — provedor de identidade do GitHub Actionsaws iam create-open-id-connect-provider \ --url https://token.actions.githubusercontent.com \ --client-id-list sts.amazonaws.comPara 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.
3. Restrinja por repositório e por referência
Seção intitulada “3. Restrinja por repositório e por referência”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 protegidorepo:empresa/loja:ref:refs/tags/v* ← aceitável: só tags de releaserepo:empresa/* ← perigoso: qualquer repositório da organizaçãorepo:* ← nuncaDê ao papel apenas as permissões do deploy — publicar imagem, atualizar o serviço. Não use papel de administrador “por enquanto”.
4. Assuma a identidade no workflow
Seção intitulada “4. Assuma a identidade no workflow”name: deployon: 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-deploymentNenhum secrets.AWS_* aparece no arquivo. Esse é o resultado esperado.
5. Audite e remova o que sobrou
Seção intitulada “5. Audite e remova o que sobrou”# quem assumiu o papel, e a partir de qual workflowaws cloudtrail lookup-events --lookup-attributes \ AttributeKey=EventName,AttributeValue=AssumeRoleWithWebIdentity --max-results 20
# chaves estáticas ainda ativas — o objetivo é esta lista ficar vaziaaws 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.
Se der errado
Seção intitulada “Se der errado”| 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.
Checklist de pronto
Seção intitulada “Checklist de pronto”- 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: writee sem segredo de nuvem. - Chave estática antiga apagada no IAM e removida do repositório.
- Uso visível na trilha de auditoria.