After this lesson, you will be able to: Apply IAM users, roles, policies, the principle of least privilege, service roles, and instance profiles in real AWS workflows.
IAM is the foundation of every AWS deploy. A misconfigured IAM policy is the most common source of cloud breaches. This lesson covers the model properly.
User: a human or programmatic identity. Has long-lived credentials (password / access key). Group: a bundle of users that share policies. Lets you manage permissions at a team level. Role: an identity that can be ASSUMED by users, services, or external parties. Yields temporary credentials. Policy: JSON document declaring what's allowed / denied. Attached to users, groups, or roles.
Read this slowly; every field matters.
{"Version": "2012-10-17","Statement": [{"Sid": "AllowS3ReadOneBucket","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"] }}}]}# Effect: Allow or Deny (Deny wins over Allow)# Action: which API calls (s3:GetObject, ec2:*, etc.)# Resource: which ARNs (bucket arn for bucket-level; arn/* for object-level)# Condition: extra constraints (IP, time, MFA, tags)
`"Action": "*"` or `"Resource": "*"` means 'everything'. Convenient; dangerous. Read every policy you see and ask: could a smaller scope do the job? AWS IAM Access Analyzer generates least-privilege policies from CloudTrail history. Use it on every legacy policy. The single most common cloud breach pattern: an over-permissive IAM role assumed by a compromised service.
User: for humans. Long-lived credentials. Add MFA. Rotate keys. Role: for everything else. Services (EC2, Lambda, ECS Pods) assume roles. Get short-lived credentials automatically. No keys to rotate. Modern best practice: zero long-lived AWS access keys. Humans federate from SSO (Identity Center / Okta) into roles. Services use instance profiles / IRSA / task roles. If you have to write `AKIAxxxx` keys into a config file, you're doing it the old way.
Attach a role to the EC2 instance; SDK auto-assumes it.
# 1. Create a role with trust policy 'EC2 can assume me'{"Version": "2012-10-17","Statement": [{"Effect": "Allow","Principal": { "Service": "ec2.amazonaws.com" },"Action": "sts:AssumeRole"}]}# 2. Attach a permissions policy (e.g. S3 read for one bucket)# 3. When launching EC2 (or in instance settings), attach the role.# 4. SDK on the instance (aws-sdk in Node, boto3 in Python) auto-fetches# credentials from the instance metadata service (IMDSv2).# Result: no AWS keys on the instance. Credentials rotate automatically.# Same pattern for Lambda (execution role), ECS task role, EKS Pod IAM (IRSA).
Long-lived access keys committed to public repos. Top source of cloud breaches. AdministratorAccess attached to every role 'just in case'. Audit weekly with IAM Access Analyzer. Trust policies with Principal: *. Anyone (any AWS account) can assume the role. Always specify the account ID or condition. Inline policies vs managed: prefer managed (reusable, versioned). No conditions on MFA-required actions. Use `aws:MultiFactorAuthPresent` condition on destructive operations.
Pick the modern approach.
Sign in and purchase access to unlock this lesson.