IntermediateCloud Engineer

Write and test least-privilege IAM policies

Design an IAM policy for a Lambda function that reads from S3 and writes to DynamoDB. You will start with broad permissions, enumerate the exact API calls the function makes via CloudTrail, write a least-privilege policy with explicit denies, and verify the deny rules hold using the AWS IAM Policy Simulator.

Why this matters

Overly broad IAM policies are the most common cloud security vulnerability in real AWS accounts; and the hardest to notice because everything still works. Writing a least-privilege policy from scratch teaches you the IAM policy language, the difference between identity-based and resource-based policies, and how to use the simulator to verify your reasoning before an incident does it for you.

Before you start

Step-by-step guide

  1. 1

    Enumerate actual API calls via CloudTrail

    Temporarily attach AdministratorAccess to your Lambda role. Enable CloudTrail in the same region. Invoke the Lambda 5-10 times. Query CloudTrail for the IAM calls made by your function's role ARN. This gives you the ground truth: the exact API calls your function actually makes.

  2. 2

    Write the minimal policy

    Based on the CloudTrail output, write an IAM policy with only the specific actions (e.g., s3:GetObject, dynamodb:PutItem) on the specific resource ARNs. Add explicit Deny statements for destructive actions like s3:DeleteObject and dynamodb:DeleteTable.

  3. 3

    Attach and test with the CLI

    Swap AdministratorAccess for your custom policy. Invoke the Lambda and verify it still works. Then use aws iam simulate-principal-policy to test each action: your allows should show Match and your explicit denies should show ExplicitDeny.

  4. 4

    Add a resource condition

    Update the S3 policy to only allow access when the object key starts with a specific prefix using the s3:prefix condition key. Test that a request to a key outside the prefix is denied. Conditions are where IAM gets powerful; they scope by time, IP, tag, and dozens of other attributes.

  5. 5

    Block privilege escalation

    Add an explicit Deny for iam:AttachRolePolicy and iam:CreateUser to prevent the Lambda role from granting itself more permissions. This is the self-escalation prevention pattern; a compromised Lambda should not be able to create new IAM credentials.

  6. 6

    Document each statement

    Write a short comment above each statement in the policy JSON explaining what it does and why. Good IAM policies are self-documenting because permissions that look unnecessary get removed by the next engineer unless there is a comment explaining why they exist.

Relevant Axiom pages

What to do next

Back to Practice Lab