Joao Brietzke Blog

← voltar

Suas instâncias EC2 podem acessar a AWS sem chave nenhuma

Toda vez que eu precisava que uma aplicação na AWS acessasse o S3, eu fazia a mesma coisa: criava um usuário no IAM, gerava uma access key, colava no .env e seguia em frente.

Funciona. Mas tem um problema. E se esse .env vazar? Um git push errado, um servidor invadido. A chave continua válida até alguém perceber e revogar. Pode demorar dias.

A verdade é que, dentro da AWS, você não precisa de chave nenhuma. Suas instâncias acessam outros serviços sem guardar segredo. Vou explicar como.

A pergunta que o IAM responde

O IAM serve pra responder uma coisa só: quem pode fazer o quê, em quais recursos, sob quais condições. Se você guardar essa frase, o resto é detalhe.

Access key x role

Uma access key é um segredo que não expira. Vale até você apagar na mão. É como uma senha anotada num papel: prática, mas perigosa se vazar.

Uma role é diferente. Ela é uma identidade temporária que a sua instância assume por um tempo. Ninguém é dono dela. A instância veste a role e ganha credenciais que expiram sozinhas em poucas horas.

Pensa num crachá. A access key é o crachá fixo de um funcionário. A role é um crachá de visitante: a instância pega emprestado, usa, e ele se renova.

O código não tem credencial

Esse é um servidor Node que lista um bucket S3:

const { S3Client, ListObjectsV2Command } = require("@aws-sdk/client-s3");

// Repare: nenhuma credencial passada aqui.
const s3 = new S3Client({ region: "us-east-1" });

const data = await s3.send(new ListObjectsV2Command({ Bucket: "meu-bucket" }));

Sem .env. Sem access key. Sem secret. Rodando numa EC2 com a role certa, funciona.

O SDK da AWS procura as credenciais sozinho. Dentro da AWS, ele acha elas na própria instância, entregues pela role. Mas como isso funciona de verdade? É o que as próximas seções mostram.

Como a role funciona por dentro

Uma role tem duas partes, e cada uma responde uma pergunta diferente.

A primeira é a trust policy. Ela diz quem pode assumir a role. No nosso caso, ela diz que o serviço EC2 pode assumir. É como a etiqueta no crachá de visitante: "este crachá pode ser usado por funcionários do EC2".

A segunda é a permissions policy. Ela diz o que a role pode fazer depois de assumida. No nosso caso, ler o bucket S3.

As duas precisam existir. Trust policy sem permissão: a instância assume a role mas não faz nada. Permissão sem trust policy: ninguém consegue assumir. Juntas, elas formam a role completa.

Quem assume a role na prática é o serviço STS (Security Token Service). Ele é o cara que emite as credenciais temporárias. Quando a EC2 vai usar a role, por baixo dos panos ela está chamando o STS e dizendo "quero assumir essa role". O STS confere a trust policy, vê que o EC2 pode, e devolve as credenciais temporárias.

O refresh acontece sozinho

As credenciais que a instância recebe expiram em poucas horas. Antes de expirarem, a AWS já coloca um conjunto novo no lugar, e o SDK pega o novo na próxima chamada.

Isso se repete a vida toda da instância, sem você fazer nada. O acesso nunca para, mas cada credencial individual dura pouco. Se uma vazar, ela morre em horas. E ninguém precisa lembrar de trocar senha, porque a rotação é automática.

O instance profile

Tem uma peça que confunde e quase nenhum tutorial explica.

A EC2 não anexa uma role direto. Ela anexa um instance profile, que é um envelope em volta da role. Pensa nele como o suporte de crachá preso na máquina. A EC2 só sabe olhar pro suporte. Você encaixa o crachá (a role) nele.

No console da AWS isso acontece num clique, escondido. Pela linha de comando você vê os passos separados: cria a role, cria o instance profile, encaixa um no outro, anexa na instância.

A ordem é essa: a permissão (policy) fica dentro da role, a role fica dentro do instance profile, e o instance profile fica anexado na EC2.

Por que é mais seguro

Access key no .env: se vazar, o atacante tem acesso total por tempo indeterminado, até alguém revogar na mão.

Role na instância: não tem segredo guardado pra vazar. E se alguém pegar as credenciais temporárias, elas expiram em horas.

Quando ainda usar access key

A regra é simples:

  • Aplicação dentro da AWS (EC2, Lambda, ECS): use role.
  • Algo de fora (seu notebook, um CI externo, um sistema on-premises): aí sim use access key, porque não tem instância pra assumir role.

A access key não é o problema. O problema é usar ela dentro de uma EC2.

Bônus: só um servidor pode acessar o S3

Cenário real: você tem três servidores, uma API, um Redis e um Postgres. Só a API pode falar com o S3. Como garantir?

Simples: você anexa o instance profile só na API. Redis e Postgres não recebem a role, então não acessam o S3. Nem que tentem.

O controle não está na role. Está em onde você anexa. Cada servidor carrega só o crachá que precisa. Se o Redis for invadido, o atacante não chega no S3, porque o Redis nunca teve esse acesso.

Resumindo

O pulo do gato é parar de pensar em guardar uma chave e começar a pensar que a máquina assume uma identidade temporária.

A partir daí tudo se encaixa. O STS emite as credenciais temporárias. O instance profile liga a role na máquina. O SDK pega tudo sozinho e a rotação roda nos bastidores.

Você escreve o código uma vez, sem segredo nenhum, e ele roda seguro em produção. Depois que entendi isso, colocar access key dentro da AWS passou a parecer o que é: um risco que não precisa existir.

Desafio: faça você mesmo

Teoria é uma coisa, fazer na mão é outra. Então fica o desafio.

Eu deixei o código pronto num repositório, pra você não precisar se preocupar com a parte de programação e focar no que importa aqui: o IAM.

Código: https://github.com/JoaoVitorLima242/blog-content/tree/main/iam-role-with-s3-permission

A missão é essa:

  1. Suba esse código numa instância EC2.
  2. Crie uma role com permissão de acesso ao S3.
  3. Anexe essa role na instância.
  4. Rode a aplicação e veja ela acessar o S3.

O objetivo é fazer isso sem gerar nenhuma access key. Nada de secret no .env, nada de chave guardada na máquina. Só a role fazendo o trabalho.

Se a aplicação conseguir falar com o S3 e você não colocou uma chave sequer, parabéns: você acabou de fazer na prática tudo que esse post explicou.