IAM Least Privilege Patterns
Overview
The principle of least privilege ensures that IAM entities (users, roles, services) have only the permissions necessary to perform their tasks—nothing more. This reduces the blast radius of security incidents and meets compliance requirements.
flowchart TB
subgraph "Permission Layers"
PB[Permission Boundary]
RP[Role Policy]
RP2[Resource Policy]
end
subgraph "Effective Permissions"
EP[Intersection of All Layers]
end
PB --> EP
RP --> EP
RP2 --> EP
style EP fill:#90EE90
Key Concepts
Permission Boundaries
A permission boundary sets the maximum permissions a role can have, regardless of its attached policies. Think of it as a "ceiling" on permissions.
Service-Linked Roles
AWS-managed roles with predefined permissions for specific services. Use these when available instead of creating custom roles.
IRSA (IAM Roles for Service Accounts)
For Kubernetes workloads on EKS, IRSA allows pods to assume IAM roles without embedding credentials. This is the recommended approach for EKS.
Best Practices
- •Start with zero permissions - Add only what's needed
- •Use conditions - Restrict by IP, time, tags, or resource attributes
- •Scope to resources - Avoid
Resource: "*"when possible - •Use permission boundaries - Prevent privilege escalation
- •Prefer managed policies - For common use cases
- •Implement IRSA - For Kubernetes workloads on EKS
- •Regular access reviews - Use IAM Access Analyzer
- •Use service control policies (SCPs) - For organization-wide guardrails
Anti-Patterns to Avoid
❌ Using AdministratorAccess for applications
❌ Hardcoding credentials in code
❌ Overly permissive Resource: "*" statements
❌ Sharing IAM roles across unrelated services
❌ Long-lived access keys instead of temporary credentials
Example 1: Terraform - Lambda with Scoped Permissions + Permission Boundary
This example creates a Lambda function with:
- •A scoped IAM role limited to specific S3 bucket and DynamoDB table
- •A permission boundary to prevent privilege escalation
- •CloudWatch Logs permissions for the function's log group only
📁 Location: terraform/examples/iam-least-privilege/
Key Features
# Permission boundary - the ceiling for this role
resource "aws_iam_policy" "permission_boundary" {
name = "${local.name_prefix}-boundary"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = ["s3:*", "dynamodb:*", "logs:*"]
Resource = "*"
Condition = {
StringEquals = {
"aws:RequestedRegion" = var.aws_region
}
}
},
{
Effect = "Deny"
Action = ["iam:*", "organizations:*", "sts:AssumeRole"]
Resource = "*"
}
]
})
}
# Role with scoped policy
resource "aws_iam_role_policy" "lambda_policy" {
role = aws_iam_role.lambda.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = ["s3:GetObject", "s3:PutObject"]
Resource = "${aws_s3_bucket.data.arn}/*" # Scoped to specific bucket
}
]
})
}
Example 2: CDK - IRSA for EKS Pod with Scoped Permissions
This example creates:
- •An EKS service account with IRSA
- •A scoped IAM role for S3 and Secrets Manager access
- •Permission boundary attached to the role
📁 Location: cdk/examples/iam-least-privilege/
Key Features
// Create IRSA role with scoped permissions
const serviceAccountRole = new iam.Role(this, 'PodRole', {
assumedBy: new iam.FederatedPrincipal(
cluster.openIdConnectProvider.openIdConnectProviderArn,
{
StringEquals: {
[`${cluster.clusterOpenIdConnectIssuer}:sub`]:
`system:serviceaccount:${namespace}:${serviceAccountName}`,
[`${cluster.clusterOpenIdConnectIssuer}:aud`]: 'sts.amazonaws.com'
}
},
'sts:AssumeRoleWithWebIdentity'
),
permissionsBoundary: permissionBoundary,
});
// Add scoped S3 policy
serviceAccountRole.addToPolicy(new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: ['s3:GetObject', 's3:PutObject'],
resources: [`${dataBucket.bucketArn}/*`],
conditions: {
StringEquals: {
's3:x-amz-acl': 'bucket-owner-full-control'
}
}
}));
Validation Checklist
- • No
Resource: "*"without conditions - • Permission boundary attached to all custom roles
- • IRSA used for EKS workloads (no static credentials)
- • IAM Access Analyzer enabled
- • No inline policies with
*actions - • All roles have meaningful descriptions
- • Tags applied for ownership tracking
Related Skills
- •OIDC & IRSA Patterns - Deeper dive into IRSA
- •Policy as Code - Enforce IAM policies with OPA
- •Secrets Externalization - Never hardcode credentials