← Voltar para o blog

william@devops:~$ cat ./laboratorio/oidc-accessdenied.md

O dia em que o OIDC
quebrou sozinho.

O pipeline entrava na AWS sem nenhuma chave guardada. Até que começou a receber AccessDenied. Ninguém tinha mexido na role. Quem mudou foi o token do GitHub.

DE ONDE VEIO

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:

log do GitHub ActionsERRO
Error: Could not assume role with OIDC:
Not authorized to perform sts:AssumeRoleWithWebIdentity

Essa 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:

diagnósticoCLOUDTRAIL
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/develop

04 / 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.

01

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.

02

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.

locals.tfREAL
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'
03

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:

  1. 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.

  2. 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.

  3. 03

    AccessDenied

    O formato novo do token, este artigo inteiro.

  4. 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ê."
COMPARTILHAR IDEIAS

Quer trocar uma ideia sobre Cloud ou DevOps?

Mandar um e-mail ↗