Ingest Lambda IAM Role
Create a role for the ingestion Lambda.
Goal
Create an IAM role for the Ingestion Lambda that can:
- read raw photos from the
beetroot-rawS3 bucket - write face thumbnails to the
beetroot-thumbsS3 bucket - call Rekognition (
DetectFaces,SearchFacesByImage,IndexFaces) - write records to DynamoDB (
Photos,Persons,Occurrences) - write logs to CloudWatch
Least privilege
Do not use broad policies like AdministratorAccess. We'll grant
only the exact permissions this Lambda needs.
Create the IAM role
- Go to IAM → Roles → Create role
- Trusted entity: AWS service
- Use case: Lambda
- Click on Next
- Skip to Step 3 by clicking on Name, review and create on the step indicator
- Role name:
beetroot-ingest-role - Click Create role
Add logging permissions
- Open the role: IAM → Roles →
beetroot-ingest-role - Go to Permissions → Add permissions → Attach policies
- Select:
AWSLambdaBasicExecutionRole - Click Add Permissions
Create the permissions policy
In this step, you will build the policy yourself using the visual editor, then we’ll also provide the final JSON so you can verify your work.
Open the visual policy editor
- Open the role: IAM → Roles → beetroot-ingest-role
- Click Add permissions → Create inline policy
- Choose the Visual editor (not JSON)
-
Select service: S3
-
Under Actions:
- Expand Read
- Select:
GetObject
-
Under Resources:
- Choose Specific
- In the Object section, click Add ARN
-
In the Add ARN popup, fill:
-
Resource bucket name:
beetroot-raw -
Resource object name:
photos-raw/*
The ARN should resolve to:
-
Resource ARN:
arn:aws:s3:::beetroot-raw/photos-raw/*
-
Resource bucket name:
-
Click Add to save the ARN.
-
Click Add additional permissions (we will add S3 Thumbs Bucket next)
Why two S3 resource entries?
We read only from photos-raw/_ and write only to faces-thumbs/_ . This keeps access tightly scoped.
-
Select service: S3
-
Under Actions:
- Expand Write
- Select:
PutObject
-
Under Resources:
- Choose Specific
- In the Object section, click Add ARN
-
In the Add ARN popup, fill:
-
Resource bucket name:
beetroot-thumbs -
Resource object name:
faces-thumbs/*
The ARN should resolve to:
-
Resource ARN:
arn:aws:s3:::beetroot-thumbs/faces-thumbs/*
-
Resource bucket name:
-
Click Add to save the ARN.
-
Click Add additional permissions (we will add DynamoDB next)
-
Select service: S3
-
Under Actions, allow:
GetObjectPutObject
-
Under Resources, click Add ARN and add two resource entries:
-
Raw photos (read):
Bucket:
beetroot-rawObject:
photos-raw/* -
Thumbnails (write):
Bucket:
beetroot-thumbsObject:
faces-thumbs/*
-
-
Click Add additional permissions (we will add DynamoDB next)
-
Select service: DynamoDB
-
Under Actions:
- Expand Read and select:
-
GetItem -
Query
-
- Expand Write and select:
-
PutItem -
UpdateItem
-
- Expand Read and select:
-
Under Resources:
- Choose Specific
- In the Table section, click Add ARN
-
In the Add ARN popup, add these tables one by one (same region:
us-east-1):-
Table name:
Persons-
Resource ARN:
arn:aws:dynamodb:us-east-1:*:table/Persons
-
Resource ARN:
-
Table name:
Photos-
Resource ARN:
arn:aws:dynamodb:us-east-1:*:table/Photos
-
Resource ARN:
-
Table name:
Occurrences-
Resource ARN:
arn:aws:dynamodb:us-east-1:*:table/Occurrences
-
Resource ARN:
-
Table name:
-
Click Add to save the ARNs, then click Next.
Why Query is needed
The ingestion Lambda uses Query when reading occurrence mappings by personId,
and may use lookups during idempotency checks.
-
Select service: Rekognition
-
Under Actions:
- Expand Read and select:
-
DetectFaces -
SearchFacesByImage
-
- Expand Write and select:
-
IndexFaces
-
- Expand Read and select:
-
Under Resources:
- Choose All resources
-
Click Next to continue.
Why All resources for Rekognition?
In IAM, many Rekognition actions don't support scoping to a single collection ARN in the visual editor. The least-privilege approach here is restricting the actions to only what we need.
Save the inline policy
- Click Next
- Policy name:
BeetrootIngestPolicy - Click Create policy
Full Policy JSON
You can verify your policy configuration by switching to the JSON editor and comparing it against the policy document below. Alternatively, paste the following JSON directly to attach all required permissions at once.
Replace bucket names if yours differ.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ReadRawPhotos",
"Effect": "Allow",
"Action": ["s3:GetObject"],
"Resource": ["arn:aws:s3:::beetroot-raw/photos-raw/*"]
},
{
"Sid": "WriteFaceThumbnails",
"Effect": "Allow",
"Action": ["s3:PutObject"],
"Resource": ["arn:aws:s3:::beetroot-thumbs/faces-thumbs/*"]
},
{
"Sid": "DynamoDBAccess",
"Effect": "Allow",
"Action": [
"dynamodb:PutItem",
"dynamodb:UpdateItem",
"dynamodb:GetItem",
"dynamodb:Query"
],
"Resource": [
"arn:aws:dynamodb:us-east-1:*:table/Persons",
"arn:aws:dynamodb:us-east-1:*:table/Photos",
"arn:aws:dynamodb:us-east-1:*:table/Occurrences"
]
},
{
"Sid": "RekognitionFaceOps",
"Effect": "Allow",
"Action": [
"rekognition:DetectFaces",
"rekognition:SearchFacesByImage",
"rekognition:IndexFaces"
],
"Resource": "*"
}
]
}Checkpoint
In the role's Permissions tab, you should see:
-
AWSLambdaBasicExecutionRole -
BeetrootIngestPolicy