A startup's AWS account was compromised because a developer committed access keys to a public GitHub repository. Within four hours, attackers spun up hundreds of GPU instances in six regions for crypto mining. The AWS bill hit $50,000 before anyone noticed. The root cause was not the committed key - it was that the key had `AdministratorAccess` policy attached. One key, unlimited damage. **IAM (Identity and Access Management)** is AWS's answer to the question: who can do what, to which resources, under what conditions? Every API call to AWS - whether from the console, CLI, or your application code - goes through IAM. IAM either approves or denies the call before anything happens.
Your team of three cloud engineers should not each have root account access. Root access cannot be restricted - it can do everything including deleting the account. IAM Users are the correct model for people who need AWS access. **IAM Users** are identities for humans (or applications) that need long-term credentials. Each user gets a username + password (for console access) and optionally access keys (for CLI/API access). **IAM Groups** are collections of users. You attach policies to groups, not individual users. When a new engineer joins, you add them to the right groups and they get the right permissions automatically.
Every permission in IAM is defined as a **policy** - a JSON document that specifies what actions are allowed or denied on which resources. Reading policies fluently is a core skill. Writing them precisely is what separates engineers who secure their systems from those who leave backdoors open.
Your EC2 instance needs to read from S3 and write to DynamoDB. You could create an IAM user, generate access keys, and embed them in the app. But what happens when the key expires? When you rotate it? When the instance is replaced? IAM Roles solve all of this. **IAM Roles** are identities without long-term credentials. Instead of a username/password or access key, a role is assumed temporarily. When an EC2 instance has a role attached, the AWS SDK automatically fetches temporary credentials (valid for 1 hour) from the instance metadata endpoint and rotates them automatically. EC2 instance boots | v AWS assigns temporary credentials from the attached IAM Role | v App uses boto3/SDK - no credentials configured in code | v SDK reads credentials from http://169.254.169.254/latest/meta-data/iam/security-credentials/<role-name> | v AWS API call succeeds with the role's permissions
Theory says "use least privilege." Practice means reducing a wildcard policy to the exact set of API actions your application actually calls. The IAM Access Analyzer and CloudTrail make this possible without guessing.
Work through these steps to replace hard-coded credentials with IAM roles in a simulated two-tier app (web server + S3 storage). 1. Create an S3 bucket for app data: ```bash aws s3 mb s3://cloud-lab-app-$(date +%s) --region ap-south-1 ## Save the bucket name shown in output BUCKET_NAME="cloud-lab-app-XXXXXXXX" ``` 2. Upload a test file: ```bash echo '{"status": "healthy", "version": "1.0.0"}' > health.json aws s3 cp health.json s3://${BUCKET_NAME}/health.json ``` 3. Create an IAM role for EC2 with S3 read access: ```bash cat > ec2-trust.json << 'EOF' {"Version": "2012-10-17", "Statement": [{"Effect": "Allow", "Principal": {"Service": "ec2.amazonaws.com"}, "Action": "sts:AssumeRole"}]} EOF aws iam create-role --role-name LabAppRole --assume-role-policy-document file://ec2-trust.json ## Create a scoped policy (read only from our specific bucket) cat > lab-s3-policy.json << EOF { "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": ["s3:GetObject", "s3:ListBucket"], "Resource": ["arn:aws:s3:::${BUCKET_NAME}", "arn:aws:s3:::${BUCKET_NAME}/*"] }] } EOF aws iam put-role-policy --role-name LabAppRole --policy-name LabS3Access --policy-document file://lab-s3-policy.json aws iam create-instance-profile --instance-profile-name LabAppProfile aws iam add-role-to-instance-profile --instance-profile-name LabAppProfile --role-name LabAppRole ``` 4. Attach the instance profile to your EC2 instance: ```bash aws ec2 associate-iam-instance-profile \ --instance-id <your-instance-id> \ --iam-instance-profile Name=LabAppProfile \ --region ap-south-1 ``` 5. SSH into the EC2 instance and verify credentials work without any key configuration: ```bash ssh prod-app ## On the EC2 instance - no aws configure needed! aws s3 ls s3://${BUCKET_NAME}/ ## Expected: 2026-08-13 10:00:00 42 health.json aws s3 cp s3://${BUCKET_NAME}/health.json - ## Expected: {"status": "healthy", "version": "1.0.0"} ## Confirm this fails (write not allowed) aws s3 cp /etc/hostname s3://${BUCKET_NAME}/hostname ## Expected: An error occurred (AccessDenied) - correct! ``` **Expected result:** The EC2 instance can read from S3 without any configured credentials. Write operations are denied because the policy only allows `GetObject` and `ListBucket`. ---
A startup's AWS account was compromised because a developer committed access keys to a public GitHub repository. Within ...
Your team of three cloud engineers should not each have root account access. Root access cannot be restricted - it can d...
Every permission in IAM is defined as a policy - a JSON document that specifies what actions are allowed or denied on wh...
Your EC2 instance needs to read from S3 and write to DynamoDB. You could create an IAM user, generate access keys, and e...
Theory says "use least privilege." Practice means reducing a wildcard policy to the exact set of API actions your applic...
Work through these steps to replace hard-coded credentials with IAM roles in a simulated two-tier app (web server + S3 s...
Concept Key fact Users Long-term credentials for humans Use Groups, not individual policies Groups Collection of users A...
Aligns directly with DevOps, Site Reliability (SRE), and Platform Engineering job descriptions.