This project aims to consolidate the knowledge acquired during the "AWS Cloud Solutions Architect - Associate" readiness course by Proz, integrating S3, Amazon Rekognition and DynamoDB using a Python Lambda function.
This is a serverless application receives an image from internet users through an online form, processes it with Artificial Intelligence and describes what is on it (objects, persons, structures, etc.).
Response page has mouseover interaction to show identified label boxes. The image is saved as an object in a S3 bucket and the result is written to a DynamoDB table, for future use.
It uses AWS services and infrastructure, but works serverless - i.e. we don't need a VM running to do the magic, what results in very low cost.
Submission Form
Response page
Images stored in bucket
Data stored in DynamoDB
AWS Lambda
Receives data from the user, processes it and shows response
Amazon Rekognition
Process the image to describe what is on it
Amazon S3
Contains the home page with the submission form, stores the received image
Amazon DynamoDB
Stores the results from image analysis
-
User:
- Access a public submission form, that is stored in a S3 Bucket
- Sends an jpeg or png image with a maximum of 2 Mb size
-
Lambda function:
- Receives the form submission via HTTP
- Writes the file as an object in the S3 bucket
- Calls Rekognition to process the image
- Writes the Rekognition response to DynamoDB, along with the file name, date and time, source IP
- Returns the Rekognition response to user via HTTP
-
Let's start creating the Lambda function. Configure it to run as a Python code and allow external calls (as we are not using API Gateway in this example)
-
After creating the Lambda function, edit it to paste our python code there, then click Deploy
-
At that same page, copy the Lambda endpoint URL and put it in the form action parameter, inside our index.html
<form
id="image-form"
action="https://yourlambdaentrypointaddress.lambda-url.us-east-1.on.aws/"
method="post"
enctype="multipart/form-data"
></form>
-
Create your S3 bucket. Make sure to uncheck the Block Public Access settings:
-
Upload
index.html
file to bucket -
Go to bucket properties and enable static website hosting, setting our
index.html
file as the Index document -
Now take note of the website endpoint of this bucket. This will be our entry-point, the public URL users must access to send an image to be analyzed (it is located at the end of bucket's Properties tab):
Create a DynamoDB table. For this example, we use "filename" as Partition key.
Now that we created all resources (and we don't need to do it for Amazon Rekognition), we need to set permissions, so the Lambda function can access then at runtime.
When we create a Lambda function, AWS creates a default role for it with also a default policy, with permissions to write logs at CloudWatch. What we need to do is add the permissions needed to use the other resources there.
-
Go to IAM > Roles and find your Lambda role there. Search for the name you gave to it at creation time. Click on it.
-
In the next screen, copy this role ARN. You will need it later.
-
You will see a policy for this role. Click on it.
-
Now click on Edit button to edit the policy code
-
Taking into account the principle of least privilege, give permissions just to what this code really needs to use. You can try to do it by the console interface, or can just skip that insert the rules by hand. Anyway, if you do it right your final code must be something like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "logs:CreateLogGroup",
"Resource": "arn:aws:logs:us-east-1:ACCOUNT_ID:*"
},
{
"Effect": "Allow",
"Action": ["logs:CreateLogStream", "logs:PutLogEvents"],
"Resource": [
"arn:aws:logs:us-east-1:ACCOUNT_ID:log-group:/aws/lambda/LAMBDA_FUNCTION_NAME:*"
]
},
{
"Sid": "Rekognition",
"Effect": "Allow",
"Action": ["rekognition:DetectLabels"],
"Resource": "*"
},
{
"Sid": "DynamoDB",
"Effect": "Allow",
"Action": ["dynamodb:PutItem"],
"Resource": [
"arn:aws:dynamodb:us-east-1:ACCOUNT_ID:table/TABLE_NAME"
]
}
]
}
- At last, check S3 bucket permissions to see if our
index.html
is public to everyone. And add permissions to let our Lambda function insert objects there. You can change this at bucket's Permissions tab. Paste that role ARN you copied up there. The final code must be something like this:
{
"Version": "2012-10-17",
"Id": "Policy1726768723312",
"Statement": [
{
"Sid": "stmt-leitura-index",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::BUCKET_NAME/index.html"
},
{
"Sid": "stmt_gravacao_imagem",
"Effect": "Allow",
"Principal": {
"AWS": "LAMBDA_ROLE_ARN"
},
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::BUCKET_NAME/*"
}
]
}
To use it, just call in a browser that bucket http endpoint you copied at Preparing S3 bucket last step. Hooray!
- AWS Rekognition is available only in some regions, make sure it is available where you are creating your structure (
us-east-1
is a good choice). - You can contribute with improvements, see the Possible Improvements section below. Create a fork and make a Pull Request when ready.
- This project is for educational purposes and should not be used in production. There are some security issues to be addressed.
- The responsibility for the use of this project is the user's. The author is not responsible for any damage or loss arising from the use of this project.
- This project is subject to change without notice.
- Check file size on the back end (it is being checked just on front end)
- Optimize Lambda function to save on S3 bucket asynchronously
- Use Amazon Cognito for OAuth login, so we will know who sent each image, preventing abuse and banning abusers
- Set a daily usage limit (after OAuth validation) to avoid overloading the system
- Allow only the original form as origin, to avoid someone using our lambda function in another application elsewhere
- Turn this function into an API and use API Gateway to access it, improving security
- Create a report page with information about the images sent, reading what was stored into DynamoDB and S3
- Centralize permissions, as some are in the Lambda policy and others in the S3 bucket
This work is licensed under CC BY-NC-SA 4.0