T Techclick ← All lessons
Amazon · AWS security · Lesson 4 of 10

Roles: humans SSO, workloads assume, keys are the leak

Git history has AKIA… from an IAM user named deploy. That key can still call S3 on tc-lab-app-logs. Humans should enter through IAM Identity Center. EC2 should use an instance profile on AppEC2Role. EKS should use IRSA. Long-lived access keys on IAM users are the classic leak.

Updated 2026-08-18·18 min read·L2 primary·Quiz at end

After this page you can

The ticket

GuardDuty later (lesson 7) will scream about an access key from a strange ASN. Today you still see aws_access_key_id in the AMI’s user-data. AppEC2Role already exists. Nobody attached the instance profile.

Quick interview answer

An IAM role is assumed: STS issues temporary credentials. Humans: IAM Identity Center (SSO) → permission set → role in account 111122223333. EC2: instance profile passes AppEC2Role; the instance retrieves creds from the metadata service (prefer IMDSv2). EKS: IRSA — service account annotated with a role, trust via the cluster OIDC provider. IAM user access keys are long-lived, copied, committed, and forgotten. Do not create them for people.

Hero · no static key
Instance profile and Identity Center instead of a long-lived access key
If the credential can live in a gist, it is the wrong credential.
Lab data · dummy only

Account 111122223333 · OUs Security / Workloads · hub VPC 10.50.0.0/16 · app VPC 10.51.0.0/16 · SG sg-web · NACL acl-app · bucket tc-lab-app-logs · role AppEC2Role · TGW tgw-lab · VGW public 203.0.113.60 · on-prem FortiGate WAN 203.0.113.10. Dummy account ID. Not yours.

Mental model

PrincipalHow it assumesWhat you should see
Priya (human)Identity Center permission setassumed-role/AWSReservedSSO_…/priya
EC2 in 10.51.0.0/16Instance profile → AppEC2RoleInstance profile attached; IMDSv2; no AKIA in user-data
EKS podIRSA (service account + OIDC trust)Role trust sts:AssumeRoleWithWebIdentity
IAM user + access keyLong-lived AKIA/ASIA static pairTreat as an incident if it belongs to a person
Assume, do not embed
Identity Centerhumans · temp creds AppEC2Roleinstance profile / IRSA STS temp IAM user keyclassic leak

Same account. Two ways in. Only one belongs in production.

https://111122223333.signin.aws.amazon.com/console
Training mock · not live
VPCIAMS3CloudTrail
IAM → Roles / Identity Center

AppEC2Role + permission sets

IAM Identity Center · no long-lived user access keys
AppEC2Role
ec2.amazonaws.com (instance profile)
Least privilege to tc-lab-app-logs · no AdministratorAccess
Required on the instance · hop limit designed
Workloads assume roles. Humans SSO. Training mock.

How to choose

SituationDoDo not
Person needs console + CLIIdentity Center permission setCreate IAM user + AKIA
EC2 must talk to S3 / KMSInstance profile on AppEC2RoleKeys in user-data or AMI
Pod must talk to AWS APIsIRSANode role reused by every pod
Third-party CIOIDC assume-role (same idea as IRSA)A forever key in the pipeline secret store “for now”

Runbook

  1. Side A — humans

    Identity Center assignments for Priya. Delete IAM user access keys that belong to people. Credential report: look for access_key_1_active.

  2. Side B — compute

    Attach the instance profile to the app instance. Confirm trust policy is ec2.amazonaws.com. For EKS, annotate the service account and check the OIDC provider.

  3. Side C — prove

    From the instance: aws sts get-caller-identity shows AppEC2Role. curl IMDSv2, not v1. Grep user-data for AKIA — must be empty.

aws cli · role proof
aws iam get-role --role-name AppEC2Role --query 'Role.AssumeRolePolicyDocument'

aws iam list-instance-profiles-for-role --role-name AppEC2Role

aws iam generate-credential-report
aws iam get-credential-report --query 'Content' --output text | base64 --decode | head

# on the instance (dummy)
TOKEN=$(curl -s -X PUT http://169.254.169.254/latest/api/token -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/AppEC2Role
aws sts get-caller-identity
# Arn: arn:aws:sts::111122223333:assumed-role/AppEC2Role/i-labapp01

Four failures

1 · Keys in user-data

Anyone with ec2:DescribeInstanceAttribute can read them. Next lesson is secrets. This lesson is: do not put them there.

2 · Role exists, profile not attached

The instance still has no creds. Attach the instance profile, do not mint a user key as a shortcut.

3 · Node instance role shared by every pod

That is not IRSA. One compromised pod is every AWS permission on the node.

4 · “Break-glass IAM user” with AKIA in LastPass, used daily

That is just a human key. Identity Center + a rare root/break-glass runbook.

How to prove it

Close only when

1) Humans assume Identity Center roles. 2) The instance caller is AppEC2Role. 3) Credential report shows no people-keys. 4) User-data has no secrets.

Traps

You hearYou say
We need an access key for EC2You need an instance profile
IRSA is just the node roleIRSA is a per-service-account role via OIDC
ASIA keys in metadata are long-livedThey are temporary session creds from STS

Knowledge check

Judgment items. One best answer. Reasons send you back to the matching section.

Q1

Preferred human access to 111122223333?

Correct: b. SSO for humans.
Q2

EC2 should get AWS credentials from…

Correct: a. Instance profile.
Q3

IRSA is…

Correct: b. IAM Roles for Service Accounts.
Q4

Why are IAM user access keys the classic leak?

Correct: b. Long-lived.
Q5

Role exists but the instance cannot call S3. First check?

Correct: a. Profile attach.
Q6

get-caller-identity on the app host should show…

Correct: a. Proof.

AWS security class series: Shared + IAM · Org / OU · SG vs NACL · Role not key · KMS + Secrets · VPC endpoint · Trail + GuardDuty · TGW hub · S3 public · Interview

Sources

Related: AWS session factory · Migration series.