Estrutura Básica de Política IAM: Effect, Action, Resource e Condition

Você abre uma política IAM no console da AWS e vê um bloco JSON com quatro campos que determinam se uma requisição será permitida ou negada. Entender o que cada elemento faz — e como eles interagem — é a diferença entre uma política que funciona como esperado e uma que silenciosamente bloqueia acesso em produção.

TL;DR — Estrutura Básica de Política IAM

ElementoO que defineObrigatório?
EffectAllow ou Deny para o statementSim
ActionQuais operações de API estão no escopoSim
ResourceQuais recursos AWS são alvo da políticaSim
ConditionRestrições contextuais adicionais (IP, MFA, tags, etc.)Não

Como o Motor de Avaliação IAM Processa uma Política

Antes de dissecar cada elemento, vale entender o fluxo de decisão. Quando uma principal faz uma chamada de API, o IAM avalia todos os statements aplicáveis e segue uma ordem de precedência estrita: um Deny explícito sempre vence qualquer Allow. A ausência de Allow equivale a Deny implícito. Isso significa que a política não é apenas uma lista de permissões — é um conjunto de regras com hierarquia.

graph TD A["Requisição de API"] --> B["Coletar todas as políticas aplicáveis"] B --> C{"Existe Deny explícito?"} C -->|"Sim"| D["NEGADO — Deny explícito"] C -->|"Não"| E{"Existe Allow explícito?"} E -->|"Sim"| F["PERMITIDO"] E -->|"Não"| G["NEGADO — Deny implícito"]
  1. Requisição chega: a principal (usuário, role, serviço) faz uma chamada de API com contexto completo (ação, recurso, condições do ambiente).
  2. Coleta de políticas: o IAM reúne todas as políticas aplicáveis — identity-based, resource-based, SCPs, permission boundaries.
  3. Deny explícito: se qualquer statement com Effect: Deny corresponder, a requisição é negada imediatamente.
  4. Allow explícito: se houver pelo menos um Allow correspondente e nenhum Deny, a requisição é permitida.
  5. Deny implícito: sem Allow correspondente, a requisição é negada por padrão.

Anatomia de um Statement IAM

Uma política IAM é um documento JSON com um array de Statement. Cada statement é uma unidade de permissão independente. Veja a estrutura completa:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ExemploLeituraS3",
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::meu-bucket",
        "arn:aws:s3:::meu-bucket/*"
      ],
      "Condition": {
        "StringEquals": {
          "aws:RequestedRegion": "us-east-1"
        }
      }
    }
  ]
}

Cada campo tem responsabilidade única. Nenhum substitui o outro.

Effect: A Decisão Binária

O campo Effect aceita exatamente dois valores: Allow ou Deny. Não existe meio-termo. Um statement sem Effect é inválido.

O ponto que engana engenheiros experientes: um Deny explícito em qualquer política aplicável — incluindo SCPs da AWS Organizations ou uma resource-based policy — cancela qualquer Allow, independente de onde o Allow esteja definido. Não adianta ter dez políticas com Allow se uma SCP na conta tiver um Deny para a mesma ação.

Pense no Effect como o voto de um juiz: Allow é 'aprovado', Deny é 'vetado'. Um único veto cancela todos os votos de aprovação na pilha de avaliação.

Action: Mapeamento Direto para Operações de API

O campo Action especifica quais operações de API estão no escopo do statement. O formato é sempre serviço:Operação, por exemplo s3:GetObject ou ec2:DescribeInstances. Você pode usar o wildcard * para cobrir múltiplas ações.

"Action": "s3:*"

Isso cobre todas as operações S3 — o que raramente é o que você quer em produção. O princípio de menor privilégio exige listar explicitamente apenas as ações necessárias.

Um detalhe importante: algumas ações IAM não correspondem a chamadas de API diretas. Por exemplo, s3:ListAllMyBuckets corresponde à API ListBuckets. O nome da ação IAM e o nome da operação de API nem sempre são idênticos. A referência canônica é o AWS Service Authorization Reference.

Também existe o campo NotAction, que inverte a lógica: o statement se aplica a todas as ações exceto as listadas. Use com cautela — combinado com Effect: Allow, pode conceder mais permissões do que o esperado.

Resource: Escopo de Aplicação da Política IAM

O campo Resource define em quais recursos AWS o statement se aplica. O formato padrão é o ARN do recurso.

"Resource": [
  "arn:aws:s3:::meu-bucket",
  "arn:aws:s3:::meu-bucket/*"
]

Note que para S3 você frequentemente precisa de dois ARNs separados: um para o bucket em si (operações como s3:ListBucket) e outro com /* para os objetos dentro dele (operações como s3:GetObject). Esquecer essa distinção é uma das causas mais comuns de 'AccessDenied' que não faz sentido à primeira vista.

Algumas ações IAM não suportam restrição por recurso específico — elas exigem "Resource": "*". Ações do tipo List e Describe frequentemente se enquadram nessa categoria. Antes de aplicar um ARN específico, verifique no Service Authorization Reference se a ação suporta resource-level permissions.

O campo NotResource existe como contraparte, mas o uso é raro e arriscado pelo mesmo motivo que NotAction.

Condition: Restrições Contextuais

O campo Condition é opcional, mas é onde as políticas ganham precisão cirúrgica. Ele permite que o statement só se aplique quando condições específicas do contexto da requisição forem verdadeiras.

A estrutura é sempre: operador de condição → chave de condição → valor esperado.

"Condition": {
  "StringEquals": {
    "aws:RequestedRegion": "us-east-1"
  },
  "Bool": {
    "aws:MultiFactorAuthPresent": "true"
  }
}

Múltiplos operadores dentro de um mesmo bloco Condition são avaliados com lógica AND — todas as condições precisam ser verdadeiras para o statement se aplicar. Múltiplos valores dentro de um mesmo operador são avaliados com lógica OR.

graph LR A["Condition Block"] --> B["Operador 1
StringEquals"] A --> C["Operador 2
Bool"] B --> D["Chave: aws:RequestedRegion
Valor: us-east-1"] C --> E["Chave: aws:MultiFactorAuthPresent
Valor: true"] B -- "AND" --- C D -- "OR entre valores" --- D
  1. Operador de condição: define o tipo de comparação — StringEquals, IpAddress, Bool, ArnLike, entre outros.
  2. Chave de condição global: prefixo aws: — disponível em todos os serviços (ex: aws:SourceIp, aws:RequestedRegion).
  3. Chave de condição de serviço: prefixo do serviço — disponível apenas para ações daquele serviço (ex: s3:prefix, ec2:Region).
  4. AND entre operadores: todos os blocos de operadores precisam ser satisfeitos simultaneamente.
  5. OR entre valores: dentro de um operador, qualquer valor correspondente satisfaz a condição.

Diagnóstico Real: O 'AccessDenied' que Não Deveria Acontecer

Cenário clássico: você cria uma política com s3:GetObject Allow em um bucket específico, atribui à role, e ainda assim recebe AccessDenied nos logs do CloudTrail.

Primeira hipótese: a política está errada. Você revisa, parece correta. Segunda hipótese: permissões insuficientes. Você adiciona mais ações. Ainda falha.

A causa real, descoberta depois de meia hora: o bucket tinha uma bucket policy com um Deny explícito para aws:SourceVpc diferente do VPC endpoint configurado. A resource-based policy do bucket estava negando antes mesmo da identity-based policy ser considerada relevante.

O comando que deveria ter sido o primeiro passo:

aws iam simulate-principal-policy \
  --policy-source-arn arn:aws:iam::123456789012:role/MinhaRole \
  --action-names s3:GetObject \
  --resource-arns arn:aws:s3:::meu-bucket/arquivo.txt

O simulador IAM avalia identity-based policies, mas não avalia resource-based policies de outros serviços como bucket policies S3. Para diagnóstico completo, você precisa verificar a bucket policy separadamente:

aws s3api get-bucket-policy \
  --bucket meu-bucket \
  --query Policy \
  --output text

Deny em resource-based policy + Allow em identity-based policy = Deny. Sempre.

Interação Entre os Quatro Elementos na Avaliação

Os quatro elementos não são independentes — eles formam um filtro em camadas. Um statement só se aplica a uma requisição quando todos os elementos correspondem simultaneamente: a ação está listada em Action, o recurso alvo corresponde a Resource, e todas as Conditions são satisfeitas. Só então o Effect é aplicado.

graph LR REQ["Requisição de API"] --> FA{"Action corresponde?"} FA -->|"Não"| SKIP["Statement ignorado"] FA -->|"Sim"| FR{"Resource corresponde?"} FR -->|"Não"| SKIP FR -->|"Sim"| FC{"Conditions satisfeitas?"} FC -->|"Não"| SKIP FC -->|"Sim"| FE["Aplicar Effect
Allow ou Deny"]
  1. Filtro de Action: a operação de API chamada está no escopo do statement?
  2. Filtro de Resource: o recurso alvo da chamada corresponde ao ARN especificado?
  3. Filtro de Condition: todas as condições contextuais são satisfeitas?
  4. Aplicação do Effect: somente se todos os filtros anteriores passarem, o Effect (Allow ou Deny) é aplicado à decisão final.

Exemplos Práticos de Política IAM com os Quatro Elementos

Exemplo 1: Acesso restrito a bucket S3 por prefixo e região

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Resource": "arn:aws:s3:::meu-bucket/dados/*",
      "Condition": {
        "StringEquals": {
          "aws:RequestedRegion": "us-east-1"
        }
      }
    }
  ]
}

Exemplo 2: Deny para deleção sem MFA

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Action": [
        "s3:DeleteObject",
        "s3:DeleteBucket"
      ],
      "Resource": "*",
      "Condition": {
        "BoolIfExists": {
          "aws:MultiFactorAuthPresent": "false"
        }
      }
    }
  ]
}

Note o uso de BoolIfExists em vez de Bool. Se a chave aws:MultiFactorAuthPresent não estiver presente no contexto (como em chamadas programáticas via access key sem MFA), BoolIfExists retorna verdadeiro para a condição, aplicando o Deny. Com Bool puro, a ausência da chave faria a condição falhar, e o Deny não seria aplicado — o oposto do comportamento desejado.

Verificando Políticas na Prática com AWS CLI

Para inspecionar políticas associadas a uma role e validar o que está em vigor:

# Listar políticas attached a uma role
aws iam list-attached-role-policies \
  --role-name MinhaRole

# Ver o conteúdo de uma política gerenciada
aws iam get-policy-version \
  --policy-arn arn:aws:iam::123456789012:policy/MinhaPolitica \
  --version-id v1

# Simular uma chamada de API específica
aws iam simulate-principal-policy \
  --policy-source-arn arn:aws:iam::123456789012:role/MinhaRole \
  --action-names ec2:DescribeInstances \
  --resource-arns "*"

Próximos Passos com Estrutura de Política IAM

Dominar os quatro elementos é o ponto de partida. O próximo nível é entender como políticas de diferentes tipos interagem: identity-based policies, resource-based policies, permission boundaries e SCPs da AWS Organizations formam camadas de avaliação que se sobrepõem. Um Allow em uma camada pode ser completamente anulado por um Deny em outra.

Consulte a documentação oficial sobre lógica de avaliação de políticas IAM e o Service Authorization Reference para verificar quais ações suportam resource-level permissions e quais chaves de condição estão disponíveis por serviço.

Glossário — Termos Essenciais de Política IAM

TermoDefinição
StatementUnidade individual de permissão dentro de uma política IAM, contendo Effect, Action, Resource e opcionalmente Condition.
PrincipalEntidade (usuário, role, serviço) que faz a requisição de API avaliada pela política.
ARNAmazon Resource Name — identificador único de um recurso AWS no formato arn:aws:serviço:região:conta:recurso.
Condition KeyAtributo do contexto da requisição usado em Condition — pode ser global (aws:) ou específico de serviço.
Deny ExplícitoStatement com Effect: Deny que, quando correspondido, cancela qualquer Allow na avaliação — independente da fonte da política.

Related Posts

Comentários

Postagens mais visitadas deste blog

Variáveis de Ambiente no Lambda: Configuração, Acesso e Criptografia com KMS

Entendendo Instâncias T3 Burstáveis: CPU Credits e Por Que Seu Servidor Fica Lento

Monitoramento de Memória RAM no EC2: Por que o CloudWatch Agent é Obrigatório