Initializing Techhub.cafe

Why does a SageMaker job need an IAM execution role and what should it contain?

Updated Aug 1, 2026

Short answer

SageMaker assumes the execution role to act on your behalf — reading S3, writing logs, pulling ECR images — so the role must trust SageMaker and grant least-privilege access to exactly the resources the job needs.

Deep explanation

A training job runs on AWS-managed infrastructure, not your laptop, so it has no credentials of its own. The execution role is how it gets them: SageMaker assumes the role and the container receives temporary credentials through the instance metadata service.

A role has two halves and candidates routinely confuse them:

Trust policywho may assume the role. For SageMaker it must name sagemaker.amazonaws.com as principal.

Permissions policywhat the assumed role may do.

JSON
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": { "Service": "sagemaker.amazonaws.com" },
"Action": "sts:AssumeRole"
}]
}

A realistic least-privilege permissions policy:

JSON
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:ListBucket"],
"Resource": [
"arn:aws:s3:::company-ml-features",
"arn:aws:s3:::company-ml-features/fraud/*"
]
},
{
"Effect": "Allow",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::company-ml-models/fraud/*"
},
{
"Effect": "Allow",
"Action": ["logs:CreateLogStream", "logs:PutLogEvents", "cloudwatch:PutMetricData"],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": ["ecr:GetAuthorizationToken", "ecr:BatchGetImage", "ecr:GetDownloadUrlForLayer"],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": ["kms:Decrypt", "kms:GenerateDataKey"],
"Resource": "arn:aws:kms:eu-west-1:123456789012:key/abc-123"
}
]
}

Note the KMS statement: if the bucket uses a customer-managed key, S3 permissions alone produce a confusing AccessDenied that is actually a KMS failure. This is one of the most common real-world debugging traps.

Python
# In Studio the role is resolved for you
role = sagemaker.get_execution_role()
# Outside Studio, pass it explicitly
estimator = SKLearn(..., role="arn:aws:iam::123456789012:role/SageMakerFraudTraining")

Real-world example

A fintech gives each project its own execution role scoped to that project's S3 prefixes, so the fraud team's training job cannot read the credit team's data even though both run in one account. Roles are provisioned by Terraform alongside the buckets, and CloudTrail records every AssumeRole, giving auditors a clean answer to "which job touched this data".

Common mistakes

  • - Attaching `AmazonSageMakerFullAccess` plus `AmazonS3FullAccess` to everything. It works, and it is the finding every audit raises.
  • - Omitting the trust policy for `sagemaker.amazonaws.com`, producing a confusing "cannot assume role" failure.
  • - Forgetting `s3:ListBucket` on the bucket ARN itself — `GetObject` alone breaks prefix listing.
  • - Missing KMS permissions on encrypted buckets and misreading the resulting `AccessDenied` as an S3 problem.
  • - Reusing one role across dev and prod, which erases the blast-radius boundary between them.

Follow-up questions

  • What is the difference between the execution role and the caller's IAM user?
  • How do you stop a user passing an over-privileged role to a job?
  • How would you restrict training jobs to run only inside a VPC?

More AWS Machine Learning interview questions

View all →