Isso aconteceu no meu laboratório de estudo, no primeiro deploy do app piloto. IDs de organização, repositório e conta foram trocados por marcadores.
01 / O ERRO
Tudo certo no código. AccessDenied na tela.
O workflow estava certo, a role existia, a permissão estava lá. Mesmo assim, o passo de login na AWS falhava sempre com a mesma mensagem:
Error: Could not assume role with OIDC:
Not authorized to perform sts:AssumeRoleWithWebIdentityEssa mensagem é das mais chatas, porque ela não diz o que não bateu. Só diz que não deixou.
02 / COMO O OIDC FUNCIONA
A role só abre a porta para quem ela conhece.
Com OIDC, nenhuma chave fica guardada no GitHub. Na hora que o workflow roda, o GitHub gera um token assinado dizendo de onde ele vem: organização, repositório e branch. A AWS confere esse token com a trust policy da role. Se bater, entrega uma credencial que dura poucos minutos.
É como a portaria de um prédio: o porteiro tem uma lista com o nome de quem pode subir. Se o crachá vier com o nome escrito diferente da lista, a pessoa não entra, mesmo sendo ela.
03 / A INVESTIGAÇÃO
O CloudTrail mostra o crachá que chegou.
Toda tentativa de assumir uma role fica registrada no CloudTrail, inclusive as que falham. E o evento mostra exatamente o que veio no token. Foi aí que achei a resposta:
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=EventName,AttributeValue=AssumeRoleWithWebIdentity \
--max-results 5 --query 'Events[].CloudTrailEvent' --output text
# o que chegou no token:
# repo:minha-org@<org_id>/app-front@<repo_id>:ref:refs/heads/develop
# o que a role esperava:
# repo:minha-org/app-front:ref:refs/heads/develop04 / A CAUSA
O nome veio com o RG junto.
O GitHub passou a mandar, junto com o nome da organização e do repositório, o ID numérico de cada um. A role estava esperando só o nome. O crachá era o mesmo, só que agora com o RG impresso do lado, e a lista da portaria não sabia disso.
E faz sentido o GitHub ter mudado. Nome de repositório pode mudar, pode ser apagado e criado de novo. O ID, não. Com o ID na conta, um repositório recriado com o mesmo nome não herda a permissão de ninguém por engano.
05 / A CORREÇÃO
Corrigi no módulo, não no projeto.
O módulo aceita o formato novo
Ajustei a validação do módulo de OIDC para aceitar org@id/repo@id e publiquei uma versão nova. Quem usa o módulo ganha a correção só subindo a versão.
A stack monta o formato certo sozinha
Na stack, os IDs viraram variáveis. Se estiverem preenchidos, o Terraform monta o formato novo; se não, usa o antigo.
oidc_repository = {
front = (
var.github_org_id != null && var.front.repository_id != null
? "${var.github_org}@${var.github_org_id}/${var.front.repository}@${var.front.repository_id}"
: "${var.github_org}/${var.front.repository}"
)
}
# descobrir os IDs:
# gh api repos/<org>/<repo> --jq '.owner.id, .id'E testei o caminho triste também
Depois de corrigir, rodei o deploy pela branch errada de propósito. A AWS recusou, como devia. Teste de segurança bom é o que prova que a porta fecha, não só que ela abre.
06 / OS OUTROS ERROS
Não foi o único erro daquele dia.
O primeiro deploy do piloto foi uma sequência de lições:
- 01
"workflow was not found"
O repositório dos workflows reutilizáveis é privado. Precisa liberar o acesso para a organização em Settings → Actions → Access.
- 02
Variável que não chegava
Criei uma variável depois que o run já tinha começado. Ela só vale para os próximos runs, então foi preciso disparar de novo.
- 03
AccessDenied
O formato novo do token, este artigo inteiro.
- 04
Imagem reprovada
O Trivy barrou a imagem base. Mas isso é assunto para outro artigo.
07 / APRENDIZADOS
O que eu levo dessa.
CloudTrail primeiro antes de mexer na role, veja o que de fato chegou.
Corrigir na fonte o ajuste foi no módulo, então todo projeto que usa ganha junto.
Testar a porta fechando deploy pela branch errada tem que ser recusado.
ID é melhor que nome nome muda; ID não.
william@devops:~$ echo $LESSON_LEARNED
"Quando a AWS diz não, o CloudTrail diz por quê."