Crisp answer: IAM (Identity and Access Management) controls who can do what in AWS. AWS evaluates permissions using a deny-by-default model: access is denied unless explicitly allowed, and an explicit deny always wins.
IAM entities:
Users: Individual people or applications with long-term credentials
Groups: Collections of users that share permissions
Roles: Assumed by services, applications, or users — short-term credentials
via STS (Security Token Service)
Policy types (in evaluation order):
1. Service Control Policies (SCPs) — org-level ceiling, cannot grant above this
2. Resource-based policies — attached to S3 buckets, KMS keys, etc.
3. Identity-based policies — attached to users, groups, roles
4. Permission boundaries — maximum permissions an entity can have
5. Session policies — passed when assuming a role
The evaluation logic:
1. Default deny — start with no access
2. Evaluate all applicable policies
3. If any policy has an explicit Deny → DENY (regardless of any Allow)
4. If any policy has an Allow → ALLOW
5. If no policy has an Allow → DENY (implicit deny)
Policy structure:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowS3ReadOnly",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::my-bucket",
"arn:aws:s3:::my-bucket/*"
],
"Condition": {
"StringEquals": {
"aws:RequestedRegion": "eu-west-2"
}
}
}
]
}
IAM Roles for Services:
EC2 instances, Lambda functions, EKS pods — they all assume IAM roles. The role's trust policy defines who can assume it:
{
"Statement": [{
"Effect": "Allow",
"Principal": { "Service": "lambda.amazonaws.com" },
"Action": "sts:AssumeRole"
}]
}
IRSA — IAM Roles for Service Accounts (EKS):
Pods on EKS assume IAM roles via OIDC federation:
resource "aws_iam_role" "s3_reader" {
assume_role_policy = jsonencode({
Statement = [{
Effect = "Allow"
Principal = { Federated = aws_iam_openid_connect_provider.eks.arn }
Action = "sts:AssumeRoleWithWebIdentity"
Condition = {
StringEquals = {
"${aws_iam_openid_connect_provider.eks.url}:sub" =
"system:serviceaccount:default:s3-reader"
}
}
}]
})
}
Useful IAM debugging commands:
# Simulate what a principal can do
aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::123456789:role/my-role \
--action-names s3:GetObject \
--resource-arns arn:aws:s3:::my-bucket/key
# See effective permissions (what an entity can do)
aws iam get-policy --policy-arn arn:aws:iam::123456789:policy/my-policy
aws iam list-attached-role-policies --role-name my-role
aws iam list-role-policies --role-name my-role # inline policies
# Who has access to an S3 bucket?
aws s3api get-bucket-policy --bucket my-bucket
What to say in the interview:
"IAM is deny by default: you need an explicit allow and no explicit deny. The evaluation hierarchy matters: SCPs set the ceiling for the whole org, then identity-based policies, then resource-based policies. An explicit deny anywhere in the chain always wins. For EKS pods I use IRSA so each pod's service account assumes a specific IAM role with only the permissions that pod needs — no broad instance profile permissions shared across all pods on the node."