IAM for Data Pipelines: Least Privilege in Practice
Roles vs users, how a Glue job or Lambda gets permissions, writing a least-privilege policy, and keeping secrets out of code.
AWSIntermediate2 min readUpdated 11 Oct 2026
Roles, not keys
Pipelines should never use long-lived access keys. Each service assumes a role:
| Component | Assumes | Gets |
|---|---|---|
| Glue job | Glue job role | Read raw prefix, write curated prefix |
| Lambda | Lambda execution role | Read manifest, write one DynamoDB table |
| Step Functions | State machine role | Start those Glue jobs and invoke that Lambda |
A least-privilege policy
{
"Version": "2012-10-17",
"Statement": [
{ "Effect": "Allow", "Action": ["s3:GetObject"], "Resource": "arn:aws:s3:::lake/raw/*" },
{ "Effect": "Allow", "Action": ["s3:PutObject"], "Resource": "arn:aws:s3:::lake/curated/*" },
{ "Effect": "Allow", "Action": ["s3:ListBucket"], "Resource": "arn:aws:s3:::lake",
"Condition": { "StringLike": { "s3:prefix": ["raw/*", "curated/*"] } } }
]
}- Scope actions (
GetObject, nots3:*). - Scope resources to prefixes, not the whole bucket.
ListBucketapplies to the bucket ARN, limited by a prefix condition.
Secrets
Database passwords and API keys belong in Secrets Manager (or SSM Parameter Store), read at runtime by the role. They should never be in code, job parameters or environment files committed to git.
How to debug AccessDenied
- Which role made the call? Check CloudTrail.
- Is the action and the exact resource ARN allowed?
- Is there an explicit
Deny(bucket policy, SCP, KMS key policy)? - For encrypted buckets, does the role also have
kms:Decrypt?
Finished this note?
