After this lesson, you will be able to: Write AWS IAM policies that grant least-privilege access, attach them to roles, and verify enforcement in the IAM Policy Simulator.
AWS IAM is the most expressive policy language in mainstream cloud and the source of countless misconfiguration breaches when written badly. This lesson covers users vs groups vs roles, policy structure, the Policy Simulator, and the workflow real security engineers use to harden permissions in production.
A user is a long-lived identity with a password or access key. A group is a bundle of users that share the same policies. A role is an identity any principal (user, EC2 instance, Lambda, another AWS account) can assume temporarily to get short-lived credentials. Best-practice modern AWS: humans federate from an IdP via IAM Identity Center, services use roles. Long-lived access keys are an anti-pattern almost everywhere.
Every IAM policy is JSON with five fields. Read this slowly, every word matters.
{"Version": "2012-10-17","Statement": [{"Sid": "ReadOneBucket","Effect": "Allow","Action": ["s3:GetObject", "s3:ListBucket"],"Resource": ["arn:aws:s3:::my-data-bucket","arn:aws:s3:::my-data-bucket/*"],"Condition": {"IpAddress": { "aws:SourceIp": ["203.0.113.0/24"] }}}]}
Spin up a free-tier AWS account if you don't have one. Use it strictly for learning, never store real data.
Create an S3 bucket called 'iam-lab-<your-initials>' and upload a sample text file
IAM > Policies > Create policy > JSON. Paste the policy above with your bucket ARN
Name it S3-LabBucket-Read
Create a new IAM user lab-reader, attach the policy directly (skip a group for this drill)
Open the IAM Policy Simulator (policysim.aws.amazon.com) and simulate s3:GetObject on your bucket as lab-reader, confirm Allowed
Simulate s3:DeleteObject on the same bucket, confirm Denied
Generate an access key for lab-reader temporarily, configure the AWS CLI with it, run `aws s3 ls s3://iam-lab-<initials>` and confirm it works; then run `aws s3 rm` and confirm it fails
Delete the access key when you're done
S3 bucket with `"Principal": "*"` in its bucket policy (any AWS account can read). EC2 instance role with `AdministratorAccess` attached for convenience (an SSRF on that instance = full account compromise). Cross-account role with weak ExternalId or no Conditions (third-party SaaS like Datadog or Wiz needs ExternalId enforced). Long-lived access keys committed to public GitHub (still the #1 source of cloud breaches per Mandiant, 2025). Use AWS IAM Access Analyzer + GuardDuty to catch all of these.
Pick the right pattern for service-to-service auth.
Sign in and purchase access to unlock this lesson.