Based on the MLS-C01 exam guideReport an error
AccessDenied, suspect the execution role first.enable_network_isolation.An ML system gathers sensitive training data, expensive model artifacts, and broad permissions in one place. If it leaks, data theft, model theft, and permission abuse all happen at once.
┌──────────────────────────────────┐
│ SageMaker training / inference │
│ workloads │
└────────────────┬─────────────────┘
┌────────────────────────────┼────────────────────────────┐
│ │ │
① IAM execution role ② VPC isolation ③ KMS encryption
"who does what" "where it communicates" "who can unlock it"
│ │ │
- least-privilege policy - private subnets - S3 SSE-KMS
- trust policy - VPC endpoints - volume_kms_key
- scoped to S3/KMS paths - security groups - output_kms_key
- network isolation - inter-node traffic encryptionSageMaker training jobs and endpoints run with the permissions of an Execution Role. If you grant this role too much, the damage from a breach grows accordingly. Give least privilege only for the S3 paths and KMS keys that are needed.
| Aspect | User credentials | SageMaker execution role |
|---|---|---|
| Who uses it | People using the console, CLI, or SDK | Training containers, endpoints, processing jobs |
| When it is evaluated | When CreateTrainingJob is called | When accessing S3, KMS, and ECR while the job runs |
| Required permissions | sagemaker:CreateTrainingJob, iam:PassRole | s3:GetObject, kms:Decrypt, ecr:GetAuthorizationToken, etc. |
| Common symptom | Job creation itself fails | The job starts but fails when reading data |
If a user can read the bucket fine in the console but only the training job gets AccessDenied, it is almost always an execution role problem. For a user to pass a role to a service, iam:PassRole is also required separately.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject"],
"Resource": [
"arn:aws:s3:::ml-train-bucket/data/*",
"arn:aws:s3:::ml-train-bucket/output/*"
]
},
{
"Effect": "Allow",
"Action": ["kms:Decrypt", "kms:GenerateDataKey"],
"Resource": "arn:aws:kms:us-east-1:111122223333:key/abcd-efgh"
}
]
}kms:Decrypt for reads and kms:GenerateDataKey for writes as well.The Trust Policy separately restricts "who can assume this role."
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": { "Service": "sagemaker.amazonaws.com" },
"Action": "sts:AssumeRole"
}]
}Training job gets AccessDenied on S3
│
① Are you looking at the "execution role" permissions, not the user's?
└ No → check the execution role ARN first
│
② Does the execution role policy include that bucket/prefix?
└ No → fix the s3:GetObject resource scope
│
③ Is there an explicit Deny in the bucket policy?
└ Yes → Deny always wins. Fix the bucket policy
│
④ Is the object SSE-KMS?
└ Yes → check kms:Decrypt / GenerateDataKey + the key policy
│
⑤ Is the job running inside a VPC?
├ Yes → check the VPC endpoint policy, routing, and security groups
└ No → check organization SCPs and the Permissions BoundaryOn the exam, "the training job cannot access S3 (AccessDenied)" is usually insufficient execution role permissions, not a user permission problem. Conversely, "the role can access all buckets" violates least privilege. Remember that the principal of the permissions is the execution role.
⚠️ Pitfall: In IAM, an explicit
Denytakes precedence over anyAllow. If even one of the role policy, bucket policy, or SCP denies, opening up everything else will not let the request through.
By default, SageMaker jobs can reach the internet from the AWS-managed network. For sensitive data you must block this. Use VpcConfig to place the job in a private subnet of your own VPC, and use VPC endpoints to reach S3 and other services without the internet.
estimator = Estimator(
image_uri=image, role=role,
instance_count=1, instance_type="ml.m5.xlarge",
subnets=["subnet-priv-a", "subnet-priv-b"],
security_group_ids=["sg-0123456789"],
encrypt_inter_container_traffic=True, # encrypt traffic between distributed training nodes
enable_network_isolation=True, # block the container's external network access
)| Option | What it does | What it blocks | What it does not block |
|---|---|---|---|
subnets | Attaches the job to an ENI in the specified VPC subnets | Arbitrary paths through the managed network | If the subnet has an internet route, traffic still goes out |
security_group_ids | Instance-level inbound/outbound filter | Ports and destinations that are not allowed | Exfiltration to destinations that are already allowed |
enable_network_isolation | Blocks all network calls from the container | All outbound communication from the container code | Input download and artifact upload done by the platform on its behalf |
encrypt_inter_container_traffic | Encrypts traffic between distributed training nodes | Plaintext transfer between nodes | Data at rest (a separate KMS setting is needed) |
When you run untrusted third-party code or models, turning on network isolation is the default.
| Aspect | Gateway endpoint | Interface endpoint (PrivateLink) |
|---|---|---|
| Supported services | Two: S3 and DynamoDB | SageMaker API/Runtime, CloudWatch, ECR, STS, etc. |
| How it works | Adds a route to the route table | An ENI (private IP) in the subnet + private DNS |
| Pricing | No additional charge | Hourly + data processing charges |
| Access scope | Same Region, inside the same VPC | Also reachable from on premises (Direct Connect, VPN) |
| Access control | Endpoint policy | Endpoint policy + security group |
A gateway endpoint is "a routing change that diverts the path to S3 inside AWS," while an interface endpoint is "creating a private-IP entry point for the service inside my subnet."
[VPC]
┌────────────────────────────────────────────────────────────┐
│ [Private Subnet A] [Private Subnet B] │
│ training container (ENI) ◀─ distributed training (SG self-reference) ─▶ training container │
│ │ │ │
│ │ └─(Interface Endpoint)─▶ SageMaker API │
│ │ CloudWatch Logs │
│ └─(Gateway Endpoint · routing)─▶ S3 / DynamoDB │
│ │
│ ✗ No internet gateway ✗ No NAT gateway │
└────────────────────────────────────────────────────────────┘⚠️ Pitfall: With
enable_network_isolation=True, the code inside the container cannot call S3 directly. Training still runs because the platform, outside the container, handles the input channel download and artifact upload on its behalf. If the training script does a pip install at runtime or fetches more data from an external URL or S3, it fails at that point.
If you only place the job in a private subnet and do not create an S3 gateway endpoint, training cannot receive its data and stalls. "The job will not start after I isolated it" is usually a missing endpoint.
Encrypt data and models both at rest and in transit. A KMS customer managed key (CMK) controls who can decrypt.
estimator = Estimator(
...,
output_kms_key="arn:aws:kms:us-east-1:111122223333:key/abcd-efgh", # encrypt model artifacts
volume_kms_key="arn:aws:kms:us-east-1:111122223333:key/wxyz-1234", # encrypt training EBS
)| Protection point | Method | Notes |
|---|---|---|
| Training data and models in S3 | Encrypt the bucket/objects with SSE-KMS (CMK) | Read: kms:Decrypt, write: kms:GenerateDataKey |
| Training instance storage | Encrypt EBS with volume_kms_key | Not applicable to local NVMe storage types |
| Model artifact output | output_kms_key | model.tar.gz is encrypted with the specified CMK |
| Traffic between distributed training nodes | encrypt_inter_container_traffic=True | Encryption in transit |
| Endpoint communication | TLS (encryption in transit by default) | Applied with no extra setup |
| Endpoint and processing job volumes | KmsKeyId in the endpoint configuration / Processing | Inference and preprocessing follow the same principle |
| Asset | Key | Principals allowed by the key policy | Effect |
|---|---|---|---|
| Team A data and models | cmk-team-a | Team A execution role and data scientists | Team B cannot decrypt even with IAM permissions |
| Team B data and models | cmk-team-b | Team B execution role and data scientists | A breach of Team A does not spread to Team B |
| Shared audit logs | cmk-audit | Security team only | Operators cannot read or delete the logs |
If you share an AWS managed key, there is effectively no isolation within the account. Remember: isolation requirement = CMK + separate key policies.
"Encryption is on, but who can use that key?" is the real control point. The KMS key policy and IAM work together, and if the key policy denies, decryption fails even with IAM permissions. The pattern of splitting CMKs per team or project to isolate data is within exam scope.
| Service | Role | Typical stem |
|---|---|---|
| Amazon Macie | Automatically detects and classifies PII and sensitive information in S3 using ML | "Find out whether credit card numbers are mixed into the dataset" |
| SageMaker Clarify | Detects bias in data and models, explains predictions | "Provide evidence of responsible AI and fairness" |
| AWS PrivateLink | Calls SageMaker privately without the internet | "Call from on premises without going through the internet" |
| Secrets Manager | Manages and rotates external DB and API credentials outside the code | "A DB password is hardcoded in the notebook code" |
| CloudTrail | Audit log of all API calls | "Who deleted the endpoint and when" (next post) |
| Permissions Boundary / SCP | A permission ceiling that a role cannot exceed | "Keep teams from widening their own permissions" |
| Target | Option | Effect |
|---|---|---|
| Studio domain | Set the network access mode to VPC only | Studio traffic flows only into the user's VPC |
| Studio domain | Separate execution roles per user profile | Separates each user's data access scope |
| Notebook instance | Disable direct internet access | Uses only the endpoint/NAT path |
| Notebook instance | Disable root access + lifecycle configuration | Enforces standard security settings at startup |
Security Review Checklist
kms:Decrypt and kms:GenerateDataKey both present?| Stem clue | Answer to choose | Why |
|---|---|---|
| "Only the training job gets AccessDenied; the user reads fine" | Add S3 permissions to the execution role | The job runs with the execution role's permissions |
| "Training must never reach the internet" | Private subnet + VPC endpoint + network isolation | Only all three together remove the internet path |
| "Only S3 and DynamoDB need private access" | Gateway endpoint | Dedicated to those two services, no extra charge |
| "Call the SageMaker API privately from on premises" | Interface endpoint (PrivateLink) | ENI-based, so reachable from Direct Connect/VPN |
| "Data between distributed training nodes flows in plaintext" | encrypt_inter_container_traffic=True | The encryption-in-transit option |
| "Encrypt model artifacts with a specific key" | output_kms_key | The parameter dedicated to output artifacts |
| "Encrypt the training instance disk" | volume_kms_key | Encrypts the attached EBS volume |
| "Keep teams from decrypting each other's data" | Per-team CMK + separate key policies | IAM alone cannot prevent key use |
| "Decryption fails even though IAM permissions were granted" | Check the KMS key policy | Both the key policy and IAM must allow it |
| "Automatically detect whether PII is mixed into the dataset" | Amazon Macie | Dedicated to detecting and classifying sensitive data in S3 |
| "Run an untrusted third-party model" | enable_network_isolation=True | Fully blocks the container's external communication |
In the next post, we cover the other half of operations: cost optimization, CloudWatch/CloudTrail logging and auditing, and disaster recovery.
Click a choice to reveal the answer and explanation.
Question 1
Due to regulatory requirements, a training job must never have access to the internet, and it must access the S3 bucket holding the training data without traversing the internet. Which configuration is MOST appropriate?
Question 2
A SageMaker training job receives AccessDenied when accessing an S3 bucket. The user can read the same bucket in the console without problems. What is the MOST likely cause?
Question 3
You want to isolate training data and model artifacts by project team so that teams cannot decrypt each other's data. Which approach is MOST effective?
Question 4
In distributed training, you want to ensure that training data passing between nodes does not flow over the network in plaintext. Which option should you set on the SageMaker Estimator?
Question 5
You want to automatically detect and classify whether PII such as credit card numbers is unintentionally included in a training dataset stored in S3. Which service is MOST appropriate?