AWS IAM Mastery: Least Privilege at Scale with Permission Boundaries
Building a scalable IAM strategy — permission boundaries for safe delegation, ABAC with tags, SCPs as guardrails, IAM Access Analyzer for drift detection, and eliminating static credentials completely.
How IAM Goes Wrong
IAM failures follow a predictable pattern: start with AdministratorAccess for convenience, add roles as complexity grows, end up with hundreds of roles — some with wildcard permissions nobody has audited. A breach of any one could mean full account compromise.
The fix isn't manual audits. It's building a system where over-permissioning is structurally hard and violations surface automatically.
Permission Boundaries
Boundaries let you safely delegate IAM management to developers without enabling privilege escalation. The boundary sets the maximum permissions a role can have — even if the role policy grants more, the boundary limits what's effective.
resource "aws_iam_policy" "developer_boundary" {
name = "DeveloperPermissionBoundary"
policy = jsonencode({
Statement = [
{ Effect = "Allow", Action = ["s3:*","lambda:*","logs:*"], Resource = "*" },
{
# Deny creating roles WITHOUT this boundary — blocks privilege escalation
Effect = "Deny"
Action = ["iam:CreateRole","iam:PutRolePolicy"]
Resource = "*"
Condition = { StringNotEquals = {
"iam:PermissionsBoundary" = "arn:aws:iam::ACCT:policy/DeveloperPermissionBoundary"
}}
}
]
})
}
Attribute-Based Access Control (ABAC)
ABAC replaces hundreds of role-per-team policies with a single policy that uses tags. A developer with team=payments on their role automatically gets access to all resources tagged team=payments.
# One policy rule — replaces 50+ team-specific policies
{
"Effect": "Allow",
"Action": ["s3:*", "dynamodb:*", "secretsmanager:GetSecretValue"],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:ResourceTag/team": "${aws:PrincipalTag/team}",
"aws:ResourceTag/env": "${aws:PrincipalTag/env}"
}
}
}
IAM Access Analyzer
Access Analyzer continuously scans your IAM policies and resource policies for external access paths you didn't intend. It automatically creates findings for S3 buckets, KMS keys, Lambda functions, and IAM roles that are accessible from outside your account or organization. We integrate findings into our security dashboard and treat them as P1 — resolve within 24 hours.
Eliminating Static Credentials
Every static AWS access key is a ticking time bomb. Our path to zero static credentials: CI/CD uses OIDC federation (GitHub Actions → IAM role), applications use EC2 instance profiles or ECS task roles, on-prem workloads use IAM Roles Anywhere, and developers use AWS SSO with short-lived session tokens. Zero aws_access_key_id in any config file, anywhere.