1. O problema: privilégio excessivo é a norma, não a exceção
Nos dois artigos anteriores desta série, vimos como evitar que segredos vazem em texto puro e como bloquear recursos inseguros antes do apply com Policy as Code. Fechamos a série com um problema mais silencioso, porque não gera erro nem alerta: permissões de IAM concedidas com mais alcance do que o necessário. Uma role de aplicação com s3:* quando só precisa de s3:GetObject em um bucket específico. Um usuário de CI com AdministratorAccess porque "assim resolve na hora e ninguém precisa pedir mais permissão depois". Nada disso quebra nada — até o dia em que uma credencial é comprometida, e o raio de ação do atacante é exatamente do tamanho da permissão que ninguém restringiu.
2. Erros comuns de permissão excessiva
- Actions com wildcard:
"Action": "s3:*"ou"Action": "*"em vez de listar exatamente as operações necessárias (s3:GetObject,s3:PutObject). - Resources com wildcard:
"Resource": "*"quando a intenção real era restringir a um bucket ou prefixo específico. - Roles compartilhadas entre serviços diferentes: uma única role "backend-role" usada por várias Lambdas/serviços com necessidades distintas, acumulando permissões de todos ao longo do tempo porque é mais fácil reaproveitar do que criar uma nova.
- Credenciais de longa duração: access keys de usuário IAM sem rotação, em vez de roles assumidas temporariamente (via
sts:AssumeRole) ou identidades federadas (OIDC em pipelines de CI). - Permissões concedidas e nunca revisadas: um acesso liberado para resolver um incidente pontual ("dá acesso de admin no S3 pra debugar isso rápido") que nunca é removido depois.
3. Desenhando políticas mínimas: metodologia
Least privilege na prática raramente é "acertar de primeira" — é um processo iterativo:
- Comece restritivo, não permissivo. Ao criar uma role nova, liste apenas as actions que o código efetivamente chama, mesmo que isso signifique testar e ajustar algumas vezes até funcionar.
- Use os logs de acesso reais para calibrar. Ferramentas como o IAM Access Analyzer (AWS) geram recomendações de política baseadas no uso real registrado em CloudTrail — em vez de adivinhar quais actions são necessárias, você vê quais foram efetivamente chamadas em um período.
- Restrinja por
Resource, não só porAction. Permitirs3:GetObjectem*ainda é privilégio excessivo se a aplicação só precisa de um bucket. Sempre que a API do serviço suportar, especifique o ARN exato. - Adicione condições (
Condition) quando possível. Restringir por IP de origem, exigir MFA, ou limitar por tag do recurso são camadas adicionais que reduzem o impacto de uma credencial vazada.
4. Exemplo prático: de permissivo a mínimo
Política de partida, comum em código copiado de um tutorial genérico:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "s3:*", "Resource": "*" } ] } Versão com least privilege, depois de identificar que a aplicação só lê objetos de um bucket específico, sob um prefixo específico:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:GetObject", "s3:ListBucket" ], "Resource": [ "arn:aws:s3:::app-uploads-prod", "arn:aws:s3:::app-uploads-prod/incoming/*" ], "Condition": { "StringEquals": { "aws:PrincipalTag/environment": "production" } } } ] } Em Terraform, o mesmo desenho, evitando reescrever o JSON manualmente:
data "aws_iam_policy_document" "app_uploads_read" { statement { effect = "Allow" actions = [ "s3:GetObject", "s3:ListBucket", ] resources = [ aws_s3_bucket.app_uploads.arn, "${aws_s3_bucket.app_uploads.arn}/incoming/*", ] condition { test = "StringEquals" variable = "aws:PrincipalTag/environment" values = ["production"] } } } resource "aws_iam_policy" "app_uploads_read" { name = "app-uploads-read-only" policy = data.aws_iam_policy_document.app_uploads_read.json } 5. Automatizando a auditoria de acessos
Desenhar a política mínima na criação não é suficiente — permissões tendem a acumular ao longo do tempo, e é preciso um processo contínuo para detectar isso:
- IAM Access Analyzer identifica automaticamente recursos acessíveis por entidades externas à conta (buckets, roles, chaves KMS) e também gera relatórios de "permissões concedidas versus permissões usadas nos últimos 90 dias", apontando o que pode ser removido:
aws accessanalyzer list-findings \ --analyzer-arn arn:aws:access-analyzer:us-east-1:123456789012:analyzer/default \ --filter '{"status": {"eq": ["ACTIVE"]}}' - cloudsplaining, uma ferramenta open source, escaneia políticas IAM de uma conta AWS inteira e sinaliza padrões arriscados (wildcards, privilege escalation, ausência de resource constraints) em um relatório HTML:
pip install cloudsplaining cloudsplaining download --profile production cloudsplaining scan --input-file default.json --output results/ - Integrando com o pipeline de IaC: o mesmo
conftest/OPA visto no artigo anterior desta série pode avaliar documentos de política IAM gerados pelo Terraform antes do apply, bloqueando qualquer"Resource": "*"combinado com uma action de escrita, por exemplo:
package terraform.iam deny[msg] { resource := input.resource_changes[_] resource.type == "aws_iam_policy" statement := resource.change.after.policy.Statement[_] statement.Effect == "Allow" statement.Resource == "*" msg := sprintf( "política '%s' usa Resource=\"*\" — restrinja ao ARN específico", [resource.address], ) } 6. Rotação e identidades temporárias
Além de restringir o que uma credencial pode fazer, reduzir por quanto tempo ela é válida limita ainda mais o impacto de um vazamento:
- Prefira roles assumidas via
sts:AssumeRolea usuários IAM com access key fixa sempre que possível. - Em pipelines de CI, use OIDC federation (GitHub Actions, GitLab CI já suportam nativamente) para que o pipeline assuma uma role temporária sem nenhuma credencial de longa duração armazenada como secret:
# GitHub Actions assumindo uma role via OIDC, sem access key fixa permissions: id-token: write contents: read steps: - uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: arn:aws:iam::123456789012:role/github-actions-deploy aws-region: us-east-1 7. Conclusão da série
Segredos guardados corretamente, recursos validados por política antes do apply e permissões desenhadas com o mínimo privilégio necessário são três frentes independentes, mas que se reforçam: um segredo vazado importa menos se a credencial associada tem alcance limitado; uma política de IAM bem desenhada é, ela mesma, um alvo natural de checagem via Policy as Code. Nenhuma automação de infraestrutura está completa sem tratar segurança e governança como parte do pipeline, não como uma revisão manual que acontece (ou não) antes de ir para produção.
Imagem de capa: Logo oficial da HashiCorp, mantenedora do Vault — Wikimedia Commons
Referências: