By Fatskills Exam Guides Team — the exam nerds behind 28,500+ quizzes and 2.1M practice questions across 500+ global exams.
A Hyper-Practical, Zero-Fluff Study Guide for AWS SAA-C03
You’re a cloud engineer at a fintech startup. Your team just migrated a legacy monolith to AWS, and now every developer, CI/CD pipeline, and microservice needs access to S3, DynamoDB, and Lambda—but no one should have admin rights. Your CISO demands least privilege, your DevOps lead wants automated deployments, and your CFO is watching costs like a hawk.
IAM Policy Types are the tools you’ll use to: - Grant permissions (e.g., "Allow this Lambda function to read from S3").- Restrict permissions (e.g., "No one can delete production databases").- Delegate permissions safely (e.g., "Let developers manage their own IAM roles, but only within a boundary").
If you ignore this:- Your S3 bucket gets publicly exposed (hello, data breach).- Your CI/CD pipeline fails silently because the IAM role lacks permissions.- Your developers accidentally delete production resources (RIP, weekend plans).
If you master this:- You automate secure access without manual ticketing.- You audit permissions in minutes (not days).- You pass the AWS SAA exam with confidence.
AmazonS3ReadOnlyAccess
json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::my-bucket/*" } ] }
json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::123456789012:root" }, "Action": "s3:*", "Resource": ["arn:aws:s3:::my-bucket", "arn:aws:s3:::my-bucket/*"] } ] }
AdministratorAccess
json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["s3:*", "dynamodb:*"], "Resource": "*" } ] }
AmazonEC2FullAccess
"Principal": { "Service": "lambda.amazonaws.com" }
"Principal": "*"
json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }
aws --version
my-secure-bucket-123
Goal: Allow a Lambda function to read from S3.
# Create a trust policy (lambda-trust-policy.json) cat > lambda-trust-policy.json <<EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } EOF # Create the role aws iam create-role --role-name LambdaS3ReadRole --assume-role-policy-document file://lambda-trust-policy.json # Attach an identity-based policy (S3 read-only) aws iam attach-role-policy --role-name LambdaS3ReadRole --policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
Verify:
aws iam list-attached-role-policies --role-name LambdaS3ReadRole
(Should show AmazonS3ReadOnlyAccess.)
Goal: Allow cross-account access (e.g., 123456789012 can read the bucket).
123456789012
# Create a bucket policy (bucket-policy.json) cat > bucket-policy.json <<EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::123456789012:root" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::my-secure-bucket-123/*" } ] } EOF # Apply the policy aws s3api put-bucket-policy --bucket my-secure-bucket-123 --policy file://bucket-policy.json
aws s3api get-bucket-policy --bucket my-secure-bucket-123
(Should show the policy.)
Goal: Ensure the Lambda role can only access S3 (no DynamoDB, EC2, etc.).
# Create a boundary policy (boundary-policy.json) cat > boundary-policy.json <<EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "s3:*", "Resource": "*" } ] } EOF # Create the boundary aws iam create-policy --policy-name S3OnlyBoundary --policy-document file://boundary-policy.json # Attach the boundary to the role aws iam put-role-permissions-boundary --role-name LambdaS3ReadRole --permissions-boundary arn:aws:iam::YOUR_ACCOUNT_ID:policy/S3OnlyBoundary
aws iam get-role --role-name LambdaS3ReadRole
(Check PermissionsBoundary in the output.)
PermissionsBoundary
Goal: Confirm the Lambda role can only read S3 (not delete objects or access other services).
# Assume the role (simulate Lambda) CREDS=$(aws sts assume-role --role-arn arn:aws:iam::YOUR_ACCOUNT_ID:role/LambdaS3ReadRole --role-session-name TestSession) export AWS_ACCESS_KEY_ID=$(echo $CREDS | jq -r .Credentials.AccessKeyId) export AWS_SECRET_ACCESS_KEY=$(echo $CREDS | jq -r .Credentials.SecretAccessKey) export AWS_SESSION_TOKEN=$(echo $CREDS | jq -r .Credentials.SessionToken) # Test S3 access (should work) aws s3 ls s3://my-secure-bucket-123/ # Test DynamoDB access (should fail) aws dynamodb list-tables
(Expected: AccessDeniedException for DynamoDB.)
AccessDeniedException
*
arn:aws:s3:::my-bucket/*
Environment=Prod
Lambda-S3-Read-Role
CreateRole
AttachPolicy
Principal: "*"
"Service": "lambda.amazonaws.com"
Deny
aws iam simulate-principal-policy
Trap: Identity-based policies only work within the same account.
"How do you restrict a role to only S3 access?"
Trap: Identity-based policies alone can’t enforce max limits.
"What happens if an identity policy allows S3 access but a boundary denies it?"
"You need to allow a Lambda function in Account A to read from an S3 bucket in Account B. What’s the most secure way?"- Answer: 1. Account B: Add a resource-based policy to the S3 bucket allowing Account A’s Lambda role. 2. Account A: Attach an identity-based policy to the Lambda role granting s3:GetObject.- Why? Resource policies enable cross-account access, and identity policies enforce least privilege.
s3:GetObject
Challenge:Create an IAM role for an EC2 instance that: 1. Can only read from a specific S3 bucket (my-app-logs).2. Has a permission boundary restricting it to S3 only.3. Uses a trust policy allowing only EC2 to assume it.
my-app-logs
Solution:
# 1. Create trust policy (ec2-trust-policy.json) cat > ec2-trust-policy.json <<EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "ec2.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } EOF # 2. Create the role aws iam create-role --role-name EC2S3ReadRole --assume-role-policy-document file://ec2-trust-policy.json # 3. Create an identity policy (s3-read-policy.json) cat > s3-read-policy.json <<EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::my-app-logs/*" } ] } EOF # 4. Attach the identity policy aws iam put-role-policy --role-name EC2S3ReadRole --policy-name S3ReadPolicy --policy-document file://s3-read-policy.json # 5. Create a boundary policy (s3-only-boundary.json) cat > s3-only-boundary.json <<EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "s3:*", "Resource": "*" } ] } EOF # 6. Create and attach the boundary aws iam create-policy --policy-name S3OnlyBoundary --policy-document file://s3-only-boundary.json aws iam put-role-permissions-boundary --role-name EC2S3ReadRole --permissions-boundary arn:aws:iam::YOUR_ACCOUNT_ID:policy/S3OnlyBoundary
Why it works:- The trust policy restricts role assumption to EC2.- The identity policy grants only s3:GetObject.- The boundary ensures the role can’t do anything outside S3.
aws iam create-role --role-name MyRole --assume-role-policy-document file://trust-policy.json
aws iam attach-role-policy --role-name MyRole --policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
aws s3api put-bucket-policy --bucket my-bucket --policy file://bucket-policy.json
aws iam put-role-permissions-boundary --role-name MyRole --permissions-boundary arn:aws:iam::123456789012:policy/MyBoundary
aws iam simulate-principal-policy --policy-source-arn arn:aws:iam::123456789012:role/MyRole --action-names s3:GetObject --resource-arns arn:aws:s3:::my-bucket/*
Allow
Join 4M+ learners. Unlock unlimited quizzes, wrong-answer tracking, flashcards + reminders, study guides, and 1-on-1 challenges.