Pular para o conteúdo

AWS · parte 2 de 11

IAM: controle de acesso na AWS

Como controlar quem pode fazer o quê na AWS com usuários, roles e políticas, e as práticas que evitam permissões excessivas.

Revisada em · 15 min de leitura

Tamanho da fonte:
Largura da coluna:

O AWS IAM (Identity and Access Management) é o serviço central de controle de acesso e segurança da Amazon Web Services. Em termos simples, é o sistema que permite gerenciar quem pode entrar no seu ambiente AWS (Autenticação) e o que essas pessoas ou aplicações têm autorização para fazer (Autorização).

Ele atua como o guardião de toda a sua infraestrutura na nuvem:

aws iam seguranca
figura 1 · aws iam seguranca

Esta aula parte dos conceitos (quem é quem, o que é uma política, por que o padrão é negar) e chega a comandos que você pode rodar na AWS CLI: criar uma política de privilégio mínimo, uma role para uma Lambda ou uma EC2, assumir uma role com MFA e ler uma mensagem de AccessDenied sem chutar.

1. Pilares: Autenticação vs Autorização

  • Autenticação (AuthN): Valida a identidade de quem está acessando (login, senha, tokens MFA, Access Keys).
  • Autorização (AuthZ): Define o escopo exato do que aquela identidade autenticada tem direito de ler, criar, alterar ou deletar na AWS.
  • Conta Raiz (Root User): Ao criar a conta AWS, nasce a conta raiz com acesso irrestrito. A melhor prática absoluta de segurança da AWS é travar a conta raiz com MFA, não usá-la no dia a dia e criar usuários/grupos com permissões controladas no IAM.

A separação entre as duas perguntas parece óbvia até aparecer um erro. Um AccessDenied pode significar que a AWS não sabe quem você é (problema de autenticação, geralmente credencial errada ou expirada) ou que ela sabe, mas você não pode fazer aquilo (problema de autorização, quase sempre uma política faltando ou um Deny). Os dois erros pedem consertos diferentes, e a seção 8 mostra como distinguir.

2. Os Quatro Componentes Fundamentais

  1. Usuários (Users): Representam uma pessoa ou serviço com credenciais individuais e permanentes (senha do console ou chaves de acesso para CLI/SDKs).
  2. Grupos (User Groups): Conjuntos de usuários com permissões em comum (ex.: grupo “Devs”, grupo “DevOps”, grupo “Auditoria”). Facilita a gestão, pois a permissão anexada ao grupo é herdada por todos os seus membros.
  3. Funções (IAM Roles): Identidades sem credenciais de longo prazo (sem login/senha fixos). Funcionam como um “crachá temporário” que pode ser assumido por usuários ou por outros serviços da AWS. Exemplo: Uma instância EC2 ou uma função Lambda recebe uma Role para gravar arquivos no S3 sem precisar de chaves expostas no código fonte.
  4. Políticas (Policies): Documentos JSON que especificam explicitamente declarações de Effect (Allow ou Deny), Action (ações permitidas/negadas como s3:GetObject), e Resource (o ARN do recurso alvo).

3. A Regra de Ouro: Princípio do Menor Privilégio (Least Privilege)

Por padrão no IAM, tudo é negado (Implicit Deny). Um usuário só tem acesso a algo se houver uma política com permissão explícita (Allow). E caso exista qualquer declaração de negação explícita (Explicit Deny), ela sempre tem precedência sobre qualquer permissão concedida.

Sempre conceda estritamente o mínimo de permissões necessárias para a tarefa ser cumprida, pelo menor tempo necessário.

O padrão de negar tudo existe porque o custo de um acesso indevido costuma ser maior que o custo de pedir uma permissão a mais. Quem começa com acesso total e tenta tirar depois quase sempre esquece alguma coisa, e a permissão esquecida fica lá até alguém notar.

4. Como a AWS decide se uma ação é permitida

Quando uma identidade faz uma chamada, a AWS reúne as políticas que valem para aquela requisição e as avalia numa ordem fixa. Muita gente imagina que basta uma política dizer Allow para a porta abrir. Na prática existe uma sequência, e ela começa pelo Deny.

A primeira pergunta é se existe algum Deny explícito que case com a ação e o recurso, em qualquer política. Se existir, a resposta é negada, e nenhuma permissão em outro lugar muda isso. A segunda pergunta é se existe um Allow válido, seja na política anexada à identidade, seja na política do recurso (uma bucket policy, por exemplo). Esse Allow ainda precisa passar pelos limites: SCPs da organização, permissions boundary e políticas de sessão. Os limites não concedem nada sozinhos, eles só cortam. Uma role com Allow no S3 continua sem acesso se a SCP da organização não permitir S3. Se nenhuma política permitir, a resposta é o Implicit Deny.

iam 01 avaliacao de politica
figura 2 · iam 01 avaliacao de politica

Leia o diagrama de cima para baixo. Os documentos roxos são as permissões concedidas e os laranjas são os limites, que só aparecem no losango de Allow e nunca criam um caminho sozinhos. As duas caixas rosas são os dois jeitos de terminar negado, e a diferença entre elas é a pista para depurar. Se existe um Deny explícito em algum lugar, o bloqueio é ativo e você procura quem o escreveu. Se não existe, faltou um Allow, e a busca é por qual política deveria conceder a ação.

Essa lógica é a descrita na documentação de avaliação de políticas da AWS. Para a mesma conta, um Allow na política da identidade ou na do recurso basta, desde que nenhum limite o contrarie. Quando a identidade está numa conta que pertence a uma organização, a interseção inclui as SCPs, o que explica muitos casos de “a política diz que pode, mas não funciona”.

5. Uma política de privilégio mínimo na prática

O princípio do menor privilégio sai do papel quando você escreve a política. Considere uma função que gera relatórios diários: ela precisa ler arquivos de uma pasta específica do bucket relatorios-exemplo, listar só essa pasta e nunca conversar com o bucket sem TLS. O arquivo abaixo faz isso, e você pode salvá-lo como politica-minima.json.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "LerRelatorios",
      "Effect": "Allow",
      "Action": ["s3:GetObject"],
      "Resource": "arn:aws:s3:::relatorios-exemplo/diarios/*"
    },
    {
      "Sid": "ListarPrefixo",
      "Effect": "Allow",
      "Action": ["s3:ListBucket"],
      "Resource": "arn:aws:s3:::relatorios-exemplo",
      "Condition": {"StringLike": {"s3:prefix": ["diarios/*"]}}
    },
    {
      "Sid": "SoComTLS",
      "Effect": "Deny",
      "Action": "s3:*",
      "Resource": ["arn:aws:s3:::relatorios-exemplo", "arn:aws:s3:::relatorios-exemplo/*"],
      "Condition": {"Bool": {"aws:SecureTransport": "false"}}
    }
  ]
}

Cada declaração tem uma função. A primeira concede leitura de objetos, e o /* no fim do Resource existe porque s3:GetObject atua sobre objetos, não sobre o bucket. A segunda concede a listagem, e ela aponta para o bucket, não para os objetos, porque s3:ListBucket é uma ação sobre o bucket. A condição s3:prefix restringe a listagem a diarios/, o que impede que a função veja os nomes de outras pastas. A terceira é um Deny com aws:SecureTransport igual a false: qualquer chamada sem TLS é recusada, mesmo que outra política a permitisse. Ele vence qualquer Allow, por isso é a forma correta de obrigar TLS.

Para anexar a política como inline a uma role (o limite de tamanho de política inline de role é 10.240 caracteres, segundo a documentação de cotas do IAM):

aws iam put-role-policy \
  --role-name leitor-relatorios \
  --policy-name leitura-diarios \
  --policy-document file://politica-minima.json

Os parâmetros são --role-name (a role que recebe a política), --policy-name (um nome único dentro da role) e --policy-document (o JSON, aqui lido de um arquivo com file://). O comando não tem saída quando dá certo.

Antes de depender da política, simule a chamada. O simulador responde o que a AWS decidiria sem executar nada:

aws iam simulate-principal-policy \
  --policy-source-arn arn:aws:iam::123456789012:role/leitor-relatorios \
  --action-names s3:GetObject \
  --resource-arns arn:aws:s3:::relatorios-exemplo/diarios/2026-10-27.csv

A saída traz uma lista EvaluationResults, e o campo EvalDecision diz allowed, implicitDeny ou explicitDeny. Para este caso, espere allowed. Se você simular s3:GetObject em relatorios-exemplo/privado/x.csv, a resposta esperada é implicitDeny, porque a política não concede nada fora de diarios/. Esse formato de saída vem da referência da API de simulação; eu não rodei esses comandos contra uma conta real nesta revisão, então confira o valor exato na sua conta.

6. Roles para serviços: Lambda e EC2

Uma role é uma identidade que outra coisa assume. Quem é autorizado a assumi-la fica escrito na trust policy (política de confiança), que é a metade da role que responde “quem pode vestir este crachá”. A outra metade, a política de permissões, responde “o que o crachá pode fazer”. Essa separação é o motivo de uma role parecer incompleta quando criada sem as duas.

Para uma Lambda, a trust policy autoriza o serviço lambda.amazonaws.com. Salve este arquivo como trust-lambda.json:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {"Service": "lambda.amazonaws.com"},
      "Action": "sts:AssumeRole"
    }
  ]
}

Depois crie a role, anexe a política de logs gerenciada pela AWS e a política de negócio:

aws iam create-role \
  --role-name lambda-relatorios \
  --assume-role-policy-document file://trust-lambda.json

aws iam attach-role-policy \
  --role-name lambda-relatorios \
  --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

aws iam put-role-policy \
  --role-name lambda-relatorios \
  --policy-name leitura-diarios \
  --policy-document file://politica-minima.json

create-role devolve um JSON com um objeto Role que contém Arn, RoleName, Path e CreateDate. O Arn é o que você passa depois para a função Lambda usar como execution role. A política AWSLambdaBasicExecutionRole dá só o necessário para escrever logs no CloudWatch Logs, e a documentação da Lambda recomenda acrescentar apenas o que a função realmente usa.

Para uma EC2 o caminho é um pouco diferente, porque a EC2 não é a própria role. A instância recebe a role por meio de um instance profile, um contêiner que liga a role à instância. A trust policy é a mesma, mudando só o serviço para ec2.amazonaws.com:

aws iam create-role --role-name app-api-s3 --assume-role-policy-document file://trust-ec2.json
aws iam create-instance-profile --instance-profile-name app-api-s3
aws iam add-role-to-instance-profile --instance-profile-name app-api-s3 --role-name app-api-s3
aws ec2 associate-iam-instance-profile \
  --instance-id i-0123456789abcdef0 \
  --iam-instance-profile Name=app-api-s3

O instance profile tem o mesmo nome da role por convenção, mas não precisa ter. Uma role entra em um instance profile, e o parâmetro --role-name de add-role-to-instance-profile espera justamente esse vínculo.

iam 03 roles de servico
figura 3 · iam 03 roles de servico

O diagrama mostra por que isso importa. A aplicação dentro da EC2 e a função Lambda não guardam chave nenhuma: elas recebem credenciais temporárias da role, o SDK as usa sozinho e a AWS as renova antes de expirarem. Se o código precisa de uma chave fixa para falar com o S3, ele está num caminho que a AWS recomenda evitar, e o risco mora no dia em que essa chave vaza em um commit.

7. Assumir uma role com MFA pela CLI

Imagine que um dev precisa ler os relatórios de produção de vez em quando, e não todo dia. Em vez de dar a ele uma permissão permanente, você cria uma role com as leituras e deixa que ele a assuma só quando precisar, e só se tiver passado pelo MFA. A condição fica na trust policy. Salve como trust-mfa.json, trocando o ARN do usuário pelo seu:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {"AWS": "arn:aws:iam::123456789012:user/dev-joao"},
      "Action": "sts:AssumeRole",
      "Condition": {"Bool": {"aws:MultiFactorAuthPresent": "true"}}
    }
  ]
}

Sem a condição aws:MultiFactorAuthPresent, qualquer chamada AssumeRole vinda desse usuário seria aceita, com ou sem o segundo fator. A condição fecha essa brecha: a chamada precisa chegar com uma sessão que passou pelo MFA.

Para assumir a role, o dev informa o ARN da role, um nome de sessão (aparece nos logs do CloudTrail, por isso convém que identifique a pessoa e o motivo), o ARN do dispositivo MFA e o código de seis dígitos que o aplicativo mostra naquele momento:

aws sts assume-role \
  --role-arn arn:aws:iam::123456789012:role/producao-leitura \
  --role-session-name joao-analise-2026-10-27 \
  --serial-number arn:aws:iam::123456789012:mfa/dev-joao \
  --token-code 123456 \
  --duration-seconds 3600

--serial-number é o ARN do dispositivo MFA cadastrado no usuário. --token-code é o código que muda com o tempo, então um código antigo é recusado. --duration-seconds define quanto a sessão dura, com mínimo de 900 segundos e máximo igual à duração máxima configurada na role (que pode ir até 12 horas, segundo a documentação de cotas). Sem o parâmetro, a sessão dura uma hora.

A saída é um JSON com o objeto Credentials, que traz AccessKeyId, SecretAccessKey, SessionToken e Expiration, e um objeto AssumedRoleUser com o ARN da sessão. Para usar essas credenciais no terminal, extraia só os campos necessários e exporte-os:

read AKID SKEY TOKEN <<< "$(aws sts assume-role \
  --role-arn arn:aws:iam::123456789012:role/producao-leitura \
  --role-session-name joao-analise-2026-10-27 \
  --serial-number arn:aws:iam::123456789012:mfa/dev-joao \
  --token-code 123456 \
  --query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]' \
  --output text)"
export AWS_ACCESS_KEY_ID="$AKID" AWS_SECRET_ACCESS_KEY="$SKEY" AWS_SESSION_TOKEN="$TOKEN"
aws sts get-caller-identity

get-caller-identity é o comando mais útil para qualquer depuração de IAM: ele responde qual identidade a CLI está usando agora. A saída deve mostrar o ARN arn:aws:sts::123456789012:assumed-role/producao-leitura/joao-analise-2026-10-27. Se mostrar o usuário original, as variáveis não foram exportadas e a CLI está usando o perfil padrão.

iam 02 assume role mfa
figura 4 · iam 02 assume role mfa

O diagrama segue a ordem da chamada, de cima para baixo. A STS confere a trust policy antes de emitir qualquer credencial, e a tentativa sem o código fica barrada no começo. Repare que a role nunca entrega acesso permanente: a credencial emitida expira, e o S3 só responde enquanto a sessão existir.

A recomendação atual da AWS, segundo as boas práticas do IAM, é que pessoas usem federação com um provedor de identidade ou o IAM Identity Center, e que cargas de trabalho usem roles. Chaves de acesso de usuário ficam para casos que realmente não conseguem usar essas alternativas. A conta raiz deve ter MFA e não ser usada no dia a dia.

8. Erros comuns e como resolver

O erro mais frequente é o AccessDenied numa chamada de serviço. A mensagem costuma seguir este formato, com os valores trocados pelos da sua chamada:

An error occurred (AccessDenied) when calling the GetObject operation: User:
arn:aws:sts::123456789012:assumed-role/leitor-relatorios/sessao is not authorized
to perform: s3:GetObject on resource: arn:aws:s3:::relatorios-exemplo/privado/x.csv
because no identity-based policy allows the s3:GetObject action

Essa mensagem já diz quase tudo. O ARN após User: mostra qual identidade foi usada, e isso é o que você confere primeiro, porque a causa mais comum é a CLI estar com outro perfil. Depois, a frase final mostra se o problema é falta de Allow (como neste caso) ou um Deny explícito, que aparece com outro texto. O S3 pode responder de forma mais curta, apenas com Access Denied, e nesse caso o simulate-principal-policy da seção 5 é o caminho para descobrir a causa. A ordem de conferência é: identidade (get-caller-identity), política da identidade, política do recurso, SCP da organização e, por fim, permissions boundary.

Quando o erro acontece no AssumeRole, a mensagem segue o formato is not authorized to perform: sts:AssumeRole on resource. A causa quase sempre está na trust policy: o ARN do principal está errado, a condição de MFA não foi atendida (o código estava errado ou expirado) ou a role é de outra conta. Compare o ARN do usuário com o Principal da trust policy, caractere por caractere.

Credenciais temporárias expiram. Se um comando que funcionava de manhã passa a responder com erro de token expirado, a sessão acabou, e basta assumir a role de novo. Isso não é um problema de permissão, e refazer as políticas não resolve.

Limites de tamanho também aparecem como erro. A documentação de cotas do IAM fixa o tamanho de uma política inline de usuário em 2.048 caracteres, de grupo em 5.120 e de role em 10.240, e o de uma política gerenciada em 6.144 caracteres. Espaços em branco não contam. Quando uma política cresce demais, a solução é dividi-la em mais de uma política gerenciada, e não remover declarações para caber.

Uma chave de acesso colada num repositório é o erro mais caro desta lista. Se isso acontecer, desative a chave imediatamente, crie outra, atualize os sistemas e apague a antiga. Depois verifique o histórico do CloudTrail para ver se ela foi usada por alguém que não devia.

9. Boas práticas, com o motivo de cada uma

  • Use roles para cargas de trabalho. A Lambda e a EC2 recebem credenciais temporárias sem nenhuma chave no código, e nada precisa ser rotacionado.
  • Mantenha MFA na conta raiz e em usuários com poder administrativo. O motivo é simples: uma senha vazada sem o segundo fator não dá acesso.
  • Prefira federação ou IAM Identity Center para pessoas. Assim o acesso acaba quando a pessoa sai da empresa, sem depender de uma chave esquecida.
  • Escreva a política pelo mínimo e amplie só com motivo. Começar amplo e apertar depois costuma deixar a permissão esquecida. O IAM Access Analyzer consegue gerar políticas a partir da atividade registrada no CloudTrail, o que ajuda a chegar ao mínimo real.
  • Use Deny para regras que não podem ser quebradas, como exigir TLS. Um Deny vence qualquer Allow que apareça em outro lugar, então ele funciona como trava.

10. Exercícios

  1. Escreva uma política que permita apenas s3:PutObject num bucket de logs, com o prefixo app-a/, e explique por que ela não permite s3:GetObject. Depois simule as duas ações com simulate-principal-policy.
  2. Crie uma role para uma Lambda que lê uma tabela do DynamoDB. Além da política de logs, o que precisa ser acrescentado? Justifique cada ação que você incluir.
  3. Altere a trust policy da seção 7 para aceitar dois usuários, mas só se o MFA estiver presente. Teste a chamada assume-role sem o --token-code e descreva a mensagem que aparece.

11. Glossário

  • Principal: quem recebe ou faz uma chamada, como um usuário, uma role ou um serviço. Na trust policy, é quem pode assumir a role.
  • Trust policy: a política que diz quem pode assumir uma role.
  • Instance profile: o contêiner que liga uma role a uma instância EC2.
  • SCP (Service Control Policy): política da organização que limita o que as contas podem fazer. Não concede acesso.
  • Permissions boundary: limite máximo de permissões que uma identidade pode receber, também sem conceder acesso sozinho.
  • STS (Security Token Service): serviço que emite as credenciais temporárias usadas nas roles.

Fontes

Consultadas em 2026-10-27:

Não verificado: o formato exato da saída de simulate-principal-policy e de associate-iam-instance-profile não foi executado contra uma conta real nesta revisão. Os exemplos de saída seguem a referência da API e devem ser conferidos na sua conta.

↑ Voltar ao topo

Atalhos de teclado

Abrir busca
/
Alternar tema claro/escuro
t
Aula anterior na série
←
Próxima aula na série
→
Lista de atalhos
?