c2.2 Use a least-privilege service role for customization and import
Create a dedicated IAM service role for model customization or import that grants only the permissions the job needs, following least privilege.
Implementation guidance
How to implement on AWS
Create a custom IAM service role for the Bedrock/SageMaker customization or import job, scoped to the specific S3 buckets and KMS keys it uses, with no broader access. Separate this role from inference and administration roles.
Why customization needs its own role
Model customization (fine-tuning, distillation, continued pre-training) runs as an asynchronous job that Amazon Bedrock executes on your behalf. Bedrock assumes an IAM service role to read your training/validation data from S3, write output metrics back, and — if your data is encrypted — use your KMS key. Because that role can read your training data, it should be dedicated to customization and scoped to exactly the buckets and keys involved, not a shared or broad role.
Trust only Bedrock, and only for your account
The role's trust policy must let the Bedrock service principal assume it, constrained with aws:SourceAccount (and ideally aws:SourceArn) so a confused-deputy in another account cannot borrow it:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "Service": "bedrock.amazonaws.com" },
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": { "aws:SourceAccount": "111122223333" },
"ArnEquals": {
"aws:SourceArn": "arn:aws:bedrock:us-east-1:111122223333:model-customization-job/*"
}
}
}
]
}
Grant only the S3 (and KMS) access the job needs
The permissions policy should list the specific buckets for input data and output, nothing wider:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ReadTrainingData",
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:ListBucket"],
"Resource": [
"arn:aws:s3:::my-bedrock-training-data",
"arn:aws:s3:::my-bedrock-training-data/*"
]
},
{
"Sid": "WriteJobOutput",
"Effect": "Allow",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::my-bedrock-custom-output/*"
}
]
}
If those buckets use a customer managed KMS key, add kms:Decrypt (and kms:GenerateDataKey for the output bucket) for that specific key ARN — without it the job fails with an access error.
Keep it separate from the invoke role
The customization role reads training data; the runtime invoke role calls models (see the least-privilege IAM control). Do not merge them — a workload that only needs to invoke a model should never hold permissions to read your training corpus.
Naming note: replace the account id, Region, and bucket names. Scope aws:SourceArn to the customization-job ARN pattern so the role is only assumable for that job type.Acceptance criteria
The customization job uses a dedicated least-privilege role scoped to its buckets/keys; no shared admin or inference role is reused.
Practical implementation
How this control is implemented in each reference architecture:
A dedicated customization service role in the Generative AI account is scoped to only the specific training buckets and keys, separate from the invoke and admin roles.
- Create a dedicated IAM service role for the Bedrock/SageMaker customization job, allowing access only to the specific training/validation S3 buckets and the customization KMS key.
- Confirm this role is not the inference invoke role and not an admin role; each duty gets its own role.
- Add a permissions boundary so the customization role can never be escalated beyond its buckets/keys.
How to validate: The job runs under a dedicated role scoped to its buckets/keys; IAM Access Analyzer shows no broad access; the role is distinct from invoke/admin roles.
Avoid: Reusing an admin or inference role to run the training job because it 'already works'. A compromised training pipeline then inherits far more than it needs.
A distinct least-privilege customization role in the account is scoped to its buckets and keys and kept separate from the runtime and admin roles.
- Create a dedicated customization service role scoped to the specific training buckets and KMS key, with no broader access.
- Keep it separate from the model-invocation role and any admin role so training, inference, and administration each have their own identity.
- Attach a permissions boundary to cap the role's reach even if its policy is later edited.
How to validate: The customization job uses a dedicated role scoped to its buckets/keys; it is not the invoke or admin role; a permissions boundary is attached.
Avoid: One catch-all role for training, inference, and admin in the single account. Separate duties by role so a training compromise stays contained.
Threats addressed
- An over-permissive customization role reaching data or actions beyond the job.
- Lateral movement from a compromised training pipeline.
AWS services
Pricing
IAM roles and policies are free. You pay for the customization job (per token processed / per hour depending on the method) and for storing training data and the resulting custom model; the role itself adds no cost. See Create a service role for model customization.
Framework mappings
OWASP GenAI/LLM Top 10 (2026)
- LLM05 Data and Model Poisoning
NIST AI Risk Management Framework (AI 100-1)
- MANAGE.1 AI risks are prioritized, responded to and managed
AWS Security Hub — AI Security Best Practices
- SageMaker.3 Users should not have root access to SageMaker notebook instances
AWS Well-Architected Generative AI Lens (Security)
- GENSEC01-BP01 Grant least privilege access to foundation model endpoints
Learning resources
References
- AWS SRA for AI — Capability 2, Identity and access management
AI Security Maturity Model