How to Apply AWS IAM Least Privilege to an Over-Permissive Policy

An IAM policy that grants every action on every resource gives an attacker the keys to your whole AWS account if a credential leaks. Least privilege means scoping each policy to exactly what the role needs - one action, one resource, nothing more.

DevOps Engineerawsiamterraform

The problem with wildcard IAM policies

A policy like this is common in early setups and terrifying in production:

{
  "Effect": "Allow",
  "Action": "*",
  "Resource": "*"
}

If the credentials attached to this policy are ever exposed - in a log file, an environment variable, a misconfigured S3 bucket - an attacker has full control of the account. AWS Access Analyzer and security audits flag this immediately.

Write a least-privilege policy in Terraform

The deployer role only needs to read objects from one S3 bucket. Scope the policy to exactly that:

resource "aws_iam_policy" "deployer" {
  name = "deployer-policy"

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect   = "Allow"
      Action   = "s3:GetObject"
      Resource = "arn:aws:s3:::app-artifacts/*"
    }]
  })
}

Action is now a single string (s3:GetObject) instead of "*", and Resource is the specific bucket prefix ARN instead of "*". The deployer can do exactly one thing on exactly one resource.

Verify the policy after applying

After terraform apply, confirm the live policy document matches what you intended:

terraform apply -auto-approve

aws iam get-policy-version \
  --policy-arn $(terraform output -raw policy_arn) \
  --version-id v1 \
  --query 'PolicyVersion.Document'

The output should show "Action": "s3:GetObject" and the specific ARN - not wildcards.

How to scope any IAM policy

Want to try it hands-on? HeyDevJob gives you this exact setup in a live cloud workspace in your browser - edit it, run it, and see it work. Free, nothing to install.

Try it in a workspace →

What you'll practice

FAQ

What does least privilege mean in AWS IAM?

Least privilege means each IAM policy grants only the specific actions on the specific resources that the workload actually needs - no wildcards, no extra permissions. It minimizes blast radius if credentials are compromised.

How do I scope an IAM policy to a specific S3 bucket?

Set Resource to the full bucket ARN with a path prefix - e.g. 'arn:aws:s3:::my-bucket/*' for objects inside the bucket, and 'arn:aws:s3:::my-bucket' for bucket-level actions like ListBucket. Use both if you need both.

How do I find which IAM permissions a role actually uses?

Check the IAM Access Advisor tab in the AWS console for service-level usage over the last 90 days. For action-level detail, use AWS Access Analyzer to generate a least-privilege policy from CloudTrail logs.

Keep learning

Fix the Nginx 502 Bad GatewayDevOps projectRecover a Crashed Linux ServiceDevOps projectCorrect a Postgres Port MismatchDevOps projectDevOps roadmapStep by step to hiredDevOps interview questionsSTAR answersAll DevOps projectsProjects hub

Learn it by doing. Open this in a live cloud workspace, make the change yourself, and keep a record of the work you can share.

Open the workspace →