Skip to content

AWS Lambda function to analyse an image using Amazon Rekognition

Notifications You must be signed in to change notification settings

wcruz-br/ai-image-analyzer

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Serverless AI Image Analyzer

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.

Objective

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.

Screenshots

Submission Form

Submission Form

Response page

Response page

Images stored in bucket

Images stored in bucket

Data stored in DynamoDB

Data stored in DynamoDB

AWS Services used

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

Architecture

Architecture

Workflow

  1. 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
  2. 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

Putting it to work

Preparing Lambda

  1. 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)

    Lambda runtime settings Lambda advanced settings

  2. After creating the Lambda function, edit it to paste our python code there, then click Deploy

    Lambda code

  3. At that same page, copy the Lambda endpoint URL and put it in the form action parameter, inside our index.html

    Lambda entrypoint

<form
    id="image-form"
    action="https://yourlambdaentrypointaddress.lambda-url.us-east-1.on.aws/"
    method="post"
    enctype="multipart/form-data"
></form>

Preparing S3 bucket

  1. Create your S3 bucket. Make sure to uncheck the Block Public Access settings:

    Public Access settings

  2. Upload index.html file to bucket

  3. Go to bucket properties and enable static website hosting, setting our index.html file as the Index document

    static website hosting

  4. 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):

    s3 endpoint url

Preparing DynamoDB

Create a DynamoDB table. For this example, we use "filename" as Partition key.

Creating DynamoDB table

Setting Permissions

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.

  1. Go to IAM > Roles and find your Lambda role there. Search for the name you gave to it at creation time. Click on it.

    IAM Roles

  2. In the next screen, copy this role ARN. You will need it later.

    Role ARN

  3. You will see a policy for this role. Click on it.

    Finding the Lambda Policy

  4. Now click on Edit button to edit the policy code

    Policy Edit

  5. 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"
            ]
        }
    ]
}
  1. 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/*"
        }
    ]
}

Now run it!

To use it, just call in a browser that bucket http endpoint you copied at Preparing S3 bucket last step. Hooray!

Notes

  • 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.

Possible Improvements

  • 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

Acknowledgements

Authors

  • Willian Cruz

    LinkedIn GitHub

  • Caio Nunes Santos

    LinkedIn GitHub

License

This work is licensed under CC BY-NC-SA 4.0