IAM is the service for managing access permissions (identity & access). In the Travel Guide workshop, IAM is used to:
In the Travel Guide architecture:
Prerequisites:

Typically, API Gateway doesn’t need a separate IAM role to authorize User Pool. However, for API Gateway to invoke Lambda from integration, you need to add permission to Lambda (resource-based) — usually done via CLI or Console auto-create.
Purpose: Lambda needs to write logs, access S3/DynamoDB, call Cognito Admin API (if backend manages users).
Console Steps:
AWSLambdaBasicExecutionRole (CloudWatch logs)AmazonDynamoDBFullAccess (replace with restricted table-specific policy)AmazonS3ReadOnlyAccess or custom S3 policy

Policy for Article CRUD operations:
{
"Effect": "Allow",
"Action": [
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:UpdateItem",
"dynamodb:DeleteItem",
"dynamodb:Query"
],
"Resource": "arn:aws:dynamodb:*:*:table/TravelGuide-*"
}
Why these permissions?
Policy for image upload/download:
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject"
],
"Resource": "arn:aws:s3:::travel-guide-*/\*"
}
Use cases:
Policy for image analysis:
{
"Effect": "Allow",
"Action": [
"rekognition:DetectLabels",
"rekognition:DetectModerationLabels"
],
"Resource": "*"
}
Use cases:
Policy for logging:
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*"
}
Why needed?
Combined policy example:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*"
},
{
"Effect": "Allow",
"Action": [
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:UpdateItem",
"dynamodb:DeleteItem",
"dynamodb:Query",
"dynamodb:Scan"
],
"Resource": "arn:aws:dynamodb:*:*:table/TravelGuide-*"
},
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::travel-guide-*/*"
},
{
"Effect": "Allow",
"Action": [
"rekognition:DetectLabels",
"rekognition:DetectModerationLabels"
],
"Resource": "*"
}
]
}
Who can assume this role?
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
This allows Lambda service to assume the role and use its permissions.
* in Resource ARNs when possible*AWSLambdaBasicExecutionRole for logging{
"Tags": [
{
"Key": "Service",
"Value": "ArticleService"
},
{
"Key": "Environment",
"Value": "staging"
}
]
}
Lambda resource policy:
{
"Effect": "Allow",
"Principal": {
"Service": "apigateway.amazonaws.com"
},
"Action": "lambda:InvokeFunction",
"Resource": "arn:aws:lambda:*:*:function:CreateArticle",
"Condition": {
"ArnLike": {
"AWS:SourceArn": "arn:aws:execute-api:*:*:*/*/POST/articles"
}
}
}
This allows API Gateway to invoke the Lambda function.
❌ Using Administrator Access
{
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}
✅ Use Specific Permissions
{
"Effect": "Allow",
"Action": ["dynamodb:GetItem", "dynamodb:PutItem"],
"Resource": "arn:aws:dynamodb:*:*:table/Articles"
}
❌ Sharing Roles Across Services
✅ Separate Roles