Skip to content

Commit b15bf9c

Browse files
author
Archana Venkitaramanan
committed
Added files
1 parent ae11f3e commit b15bf9c

File tree

6 files changed

+304
-0
lines changed

6 files changed

+304
-0
lines changed

apigw-lambda-rekognition/README.md

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# Content safety with Image Moderation using AWS API Gateway and AWS Lambda
2+
3+
Using this sample pattern, users can access AWS API Gateway to generate a pre-signed URL through an AWS Lambda function, using which they can upload images to an Amazon S3 bucket. This URL allows secure and temporary access for uploading files directly to S3.
4+
5+
Once an image is uploaded, an S3 event triggers another Lambda function that uses the DetectModerationLabels API to analyze the content. If the image is identified as inappropriate, a notification is sent via Amazon SNS, ensuring automated content moderation and alerting.
6+
7+
Learn more about this pattern at Serverless Land Patterns: https://serverlessland.com/patterns/apigw-lambda-rekognition
8+
9+
Important: this application uses various AWS services and there are costs associated with these services after the Free Tier usage - please see the [AWS Pricing page](https://aws.amazon.com/pricing/) for details. You are responsible for any AWS costs incurred. No warranty is implied in this example.
10+
11+
## Requirements
12+
13+
* [Create an AWS account](https://portal.aws.amazon.com/gp/aws/developer/registration/index.html) if you do not already have one and log in. The IAM user that you use must have sufficient permissions to make necessary AWS service calls and manage AWS resources.
14+
* [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) installed and configured
15+
* [Git Installed](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
16+
* [Terraform](https://learn.hashicorp.cxom/tutorials/terraform/install-cli?in=terraform/aws-get-started) installed
17+
18+
## Deployment Instructions
19+
20+
1. Create a new directory, navigate to that directory in a terminal and clone the GitHub repository:
21+
```
22+
git clone https://github.com/aws-samples/serverless-patterns
23+
```
24+
1. Change directory to the pattern directory:
25+
```
26+
cd apigw-lambda-rekognition
27+
```
28+
1. From the command line, initialize terraform to downloads and installs the providers defined in the configuration:
29+
```
30+
terraform init
31+
```
32+
1. From the command line, apply the configuration in the main.tf file:
33+
```
34+
terraform apply
35+
```
36+
1. During the prompts
37+
#var.prefix
38+
- Enter a value: {enter any prefix to associate with resources}
39+
40+
#var.region
41+
- Enter a value: {enter the region for deployment}
42+
43+
## Testing
44+
45+
1. After deploying the stack, create a Subscriber for your Amazon SNS topic (For ex, your email) and confirm the subscription.
46+
https://docs.aws.amazon.com/sns/latest/dg/sns-create-subscribe-endpoint-to-topic.html
47+
48+
1. Make a POST request to the API using the following cURL command:
49+
50+
curl --location 'https://<api-id>.execute-api.<region>.amazonaws.com/dev/generate-presigned-url' --header 'Content-Type: text/plain' --data '{"object_name": "image.png", "content_type": "image/png"}'
51+
52+
Note: Replace 'api-id' with the generated API ID from Terraform, 'region' with the region where the API is deployed, 'object_name' with your desired name for the S3 object and 'content_type' with the content type of the image, for ex, png or jpeg
53+
54+
1. Get the pre-signed URL from the previous step and use the following cURL command to upload the object in S3:
55+
56+
curl --location --request PUT '<presigned-url>' --header 'Content-Type: image/png' --data '<path-of-the-object>.png'
57+
58+
Note: Replace 'presigned-url' with pre-signed URL generated in the previous step. 'Content-Type' should match the content type used to generate the pre-signed URL in the previous step. Make sure you are passing the correct path of the object in the --data parameter.
59+
60+
1. Once the object is uploaded successfully, the Lambda function will be invoked and if the image is inappropirate, a message is sent to the SNS Topic, which is then received by the subscriber.
61+
62+
## Cleanup
63+
64+
1. Delete the SNS Subscription:
65+
Go to SNS > Subsciptions > Select your Subscription and click on Delete
66+
67+
https://docs.aws.amazon.com/sns/latest/dg/sns-delete-subscription-topic.html
68+
69+
1. Delete all the objects from S3:
70+
Go to S3 > Select all the objects > Click on Delete
71+
72+
https://docs.aws.amazon.com/AmazonS3/latest/userguide/delete-objects.html
73+
https://docs.aws.amazon.com/AmazonS3/latest/userguide/delete-multiple-objects.html
74+
75+
1. Change directory to the pattern directory:
76+
```
77+
cd serverless-patterns/apigw-lambda-rekognition
78+
```
79+
80+
1. Delete all created resources
81+
```
82+
terraform destroy
83+
```
84+
85+
1. During the prompts:
86+
```
87+
Enter all details as entered during creation.
88+
```
89+
90+
1. Confirm all created resources has been deleted
91+
```
92+
terraform show
93+
```
94+
----
95+
Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
96+
97+
SPDX-License-Identifier: MIT-0
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
{
2+
"title": "Content safety with Image Moderation using AWS API Gateway and AWS Lambda",
3+
"description": "Create a Lambda function which will send a notification when an inappropriate image is uploaded in Amazon S3",
4+
"language": "Python",
5+
"level": "200",
6+
"framework": "Terraform",
7+
"introBox": {
8+
"headline": "How it works",
9+
"text": [
10+
"This sample project utilizes API Gateway to generate an S3 Pre-signed URL via Lambda function, enabling users to upload images to an S3 bucket. Upon successful upload, an S3 event triggers another Lambda function to analyze the image using DetectModerationLabels API. If the image is deemed inappropriate, a notification is sent through SNS. This ensure secure uploads and automated content moderation. Use cases include user-generated content platforms and e-commerce websites, where secure image uploads and automated content moderation are essential."
11+
]
12+
},
13+
"gitHub": {
14+
"template": {
15+
"repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/apigw-lambda-rekognition",
16+
"templateURL": "serverless-patterns/apigw-lambda-rekognition",
17+
"projectFolder": "apigw-lambda-rekognition",
18+
"templateFile": "main.tf"
19+
}
20+
},
21+
"resources": {
22+
"bullets": [
23+
{
24+
"text": "Uploading objects with presigned URLs",
25+
"link": "https://docs.aws.amazon.com/AmazonS3/latest/userguide/PresignedUrlUploadObject.html"
26+
},
27+
{
28+
"text": "Moderating content",
29+
"link": "https://docs.aws.amazon.com/rekognition/latest/dg/moderation.html"
30+
},
31+
{
32+
"text": "DetectModerationLabels",
33+
"link": "https://docs.aws.amazon.com/rekognition/latest/APIReference/API_DetectModerationLabels.html"
34+
}
35+
]
36+
},
37+
"deploy": {
38+
"text": [
39+
"terraform init",
40+
"terraform apply"
41+
]
42+
},
43+
"testing": {
44+
"text": [
45+
"See the GitHub repo for detailed testing instructions."
46+
]
47+
},
48+
"cleanup": {
49+
"text": [
50+
"terraform destroy",
51+
"terraform show"
52+
]
53+
},
54+
"authors": [
55+
{
56+
"name": "Archana V",
57+
"image": "https://media.licdn.com/dms/image/D5603AQF_QwVjCkS_UQ/profile-displayphoto-shrink_200_200/0/1670929520771?e=1724284800&v=beta&t=FFJJko4OO8h1tCFrxMyneTyRPAKmyEmIaDOYOeTaFEk",
58+
"bio": "Cloud Support Engineer at AWS",
59+
"linkedin": "archana-venkat-9b80b7184"
60+
}
61+
]
62+
}
806 Bytes
Binary file not shown.
44.1 KB
Loading

apigw-lambda-rekognition/main.tf

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
variable "region" {}
2+
3+
provider "aws" {
4+
region = "${var.region}"
5+
}
6+
variable "prefix" {
7+
description = "Prefix for S3 bucket name"
8+
type = string
9+
}
10+
resource "aws_s3_bucket" "upload_bucket" {
11+
bucket = "${lower(var.prefix)}-s3-upload"
12+
}
13+
resource "aws_sns_topic" "sns_topic" {
14+
name = "SNS-Topic"
15+
}
16+
resource "aws_iam_role" "lambda_role" {
17+
name = "${lower(var.prefix)}-lambda_execution_role"
18+
assume_role_policy = jsonencode({
19+
Version = "2012-10-17",
20+
Statement = [
21+
{
22+
Effect = "Allow",
23+
Principal = {
24+
Service = "lambda.amazonaws.com"
25+
},
26+
Action = "sts:AssumeRole"
27+
}
28+
]
29+
})
30+
}
31+
resource "aws_iam_role_policy" "lambda_policy" {
32+
name = "lambda_policy"
33+
role = aws_iam_role.lambda_role.id
34+
policy = jsonencode({
35+
Version = "2012-10-17",
36+
Statement = [
37+
{
38+
Effect = "Allow",
39+
Action = [
40+
"logs:CreateLogGroup",
41+
"logs:CreateLogStream",
42+
"logs:PutLogEvents"
43+
],
44+
Resource = "*"
45+
},
46+
{
47+
Effect = "Allow",
48+
Action = [
49+
"s3:PutObject",
50+
"s3:GetObject",
51+
"s3:ListBucket"
52+
],
53+
Resource = [
54+
aws_s3_bucket.upload_bucket.arn,
55+
"${aws_s3_bucket.upload_bucket.arn}/*"
56+
]
57+
},
58+
{
59+
Effect = "Allow",
60+
Action = "sns:Publish",
61+
Resource = aws_sns_topic.sns_topic.arn
62+
},
63+
{
64+
Effect = "Allow",
65+
Action = "rekognition:DetectModerationLabels",
66+
Resource = "*"
67+
}
68+
]
69+
})
70+
}
71+
resource "aws_lambda_function" "generate_presigned_url" {
72+
filename = "generate_presigned_url.zip"
73+
function_name = "generate_presigned_url"
74+
role = aws_iam_role.lambda_role.arn
75+
handler = "generate_presigned_url.lambda_handler"
76+
runtime = "python3.8"
77+
timeout = 30
78+
environment {
79+
variables = {
80+
BUCKET_NAME = aws_s3_bucket.upload_bucket.bucket
81+
}
82+
}
83+
}
84+
resource "aws_lambda_function" "process_s3_event" {
85+
filename = "process_s3_event.zip"
86+
function_name = "process_s3_event"
87+
role = aws_iam_role.lambda_role.arn
88+
handler = "process_s3_event.lambda_handler"
89+
runtime = "python3.8"
90+
timeout = 60
91+
environment {
92+
variables = {
93+
SNS_TOPIC_ARN = aws_sns_topic.sns_topic.arn
94+
}
95+
}
96+
}
97+
resource "aws_s3_bucket_notification" "s3_bucket_notification" {
98+
bucket = aws_s3_bucket.upload_bucket.id
99+
lambda_function {
100+
lambda_function_arn = aws_lambda_function.process_s3_event.arn
101+
events = ["s3:ObjectCreated:*"]
102+
}
103+
}
104+
resource "aws_lambda_permission" "allow_s3" {
105+
statement_id = "AllowS3InvokeLambda"
106+
action = "lambda:InvokeFunction"
107+
function_name = aws_lambda_function.process_s3_event.function_name
108+
principal = "s3.amazonaws.com"
109+
source_arn = aws_s3_bucket.upload_bucket.arn
110+
}
111+
resource "aws_api_gateway_rest_api" "api" {
112+
name = "PresignedURLAPI"
113+
description = "API for generating presigned URLs"
114+
}
115+
resource "aws_api_gateway_resource" "resource" {
116+
rest_api_id = aws_api_gateway_rest_api.api.id
117+
parent_id = aws_api_gateway_rest_api.api.root_resource_id
118+
path_part = "generate-presigned-url"
119+
}
120+
resource "aws_api_gateway_method" "method" {
121+
rest_api_id = aws_api_gateway_rest_api.api.id
122+
resource_id = aws_api_gateway_resource.resource.id
123+
http_method = "POST"
124+
authorization = "NONE"
125+
}
126+
resource "aws_api_gateway_integration" "integration" {
127+
rest_api_id = aws_api_gateway_rest_api.api.id
128+
resource_id = aws_api_gateway_resource.resource.id
129+
http_method = aws_api_gateway_method.method.http_method
130+
integration_http_method = "POST"
131+
type = "AWS_PROXY"
132+
uri = "arn:aws:apigateway:${var.region}:lambda:path/2015-03-31/functions/${aws_lambda_function.generate_presigned_url.arn}/invocations"
133+
}
134+
resource "aws_lambda_permission" "allow_api_gateway" {
135+
statement_id = "AllowAPIGatewayInvoke"
136+
action = "lambda:InvokeFunction"
137+
function_name = aws_lambda_function.generate_presigned_url.function_name
138+
principal = "apigateway.amazonaws.com"
139+
source_arn = "${aws_api_gateway_rest_api.api.execution_arn}/*/*"
140+
}
141+
resource "aws_api_gateway_deployment" "deployment" {
142+
depends_on = [aws_api_gateway_integration.integration]
143+
rest_api_id = aws_api_gateway_rest_api.api.id
144+
stage_name = "dev"
145+
}
989 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)