I'm working through security audits and keep finding roles with permissions like s3:* or AdministratorAccess, often added simply to get a deployment working before a deadline. The frustrating part is that narrowing permissions is usually possible with tools such as IAM Access Analyzer, but debugging missing permissions can be slow and confusing—especially with indirect dependencies, CloudFormation or CDK bootstrapping, KMS-encrypted resources, policy size limits, and environment-specific resource names.
I recently reviewed a web portal whose Lambda roles were scoped to specific DynamoDB resources and S3 prefixes, which showed that careful permissions are achievable. At the same time, some experienced engineers are still deploying internal tools with broad EC2 or administrative access "just in case."
What processes, tooling, or guardrails have worked for your teams? How do you keep development convenient while ensuring staging and production use genuinely least-privilege roles, without making engineers resent the security process?
3 Answers
Training and feedback still matter. Many engineers know that a wildcard makes an error disappear, but they do not know how to identify the specific action, resource, or condition they actually need. Give them examples, documentation that lists required permissions for common integrations, and automated policy reviews using tools such as IaC scanners. The goal should be to make the secure option the easiest option, rather than relying on people to remember cleanup after a stressful deployment.
Centralizing all IAM work is not automatically the answer. A central team can become a bottleneck and may respond by creating one huge policy instead of several focused ones. A better model is shared ownership: security defines standards and guardrails, platform teams provide safe building blocks, and application teams own the business context. Reusable CDK or Terraform modules can grant access to the exact resource—for example, a queue construct granting only the required read permissions—without making every developer hand-write policy documents.
A practical compromise is to allow broader access in isolated development accounts, with the risk clearly understood, while making staging and production match the intended restricted model. Use permission boundaries, organization policies, and service control policies to cap the maximum possible access so that a wildcard policy cannot become unrestricted administrative power. Enforce the restricted version in CI before it reaches a shared or production account.
The environments should be equivalent where possible, especially when infrastructure is managed as code. If development is intentionally looser, the difference needs to be explicit and tested so it does not hide production failures.

Ownership and incentives matter. Managers should be accountable for overprivileged roles, while engineers should have a supported path for requesting narrowly scoped access.