AWS: Serverless REST API (API Gateway + Lambda + DynamoDb + WAF)





This project demonstrates a secure, scalable, and cost-efficient serverless REST API built using API Gateway, Lambda, DynamoDB, and protected by WAF. The architecture ensures high availability, automatic scaling, and IP-based access control for write operations, making it production-ready


 Architecture:

Client → API Gateway → Lambda → DynamoDB


🟢 STEP 1: Create DynamoDB Table:

> Go to AWS Console

> Search → DynamoDB

> Click Create table

Fill:

Table name: users

Partition key:

Name: id

Type: String

Keep On-demand capacity

> Click Create table

✅ Done.


🟢 STEP 2: Create IAM Role for Lambda:

> Go to IAM

> Click Roles

> Click Create role

> Select:

Trusted entity: AWS Service

Use case: Lambda

> Click Next

> Attach policies:

AWSLambdaBasicExecutionRole

AmazonDynamoDBFullAccess

(For learning project. In real production, use limited custom policy.)


> Name role:

lambda-dynamodb-role

> Click Create role

✅ Done.


🟢 STEP 3: Create Lambda Function

> Go to Lambda

> Click Create function


> Choose:

Author from scratch

> Fill:

Function name: users-api-function

Runtime: Python 3.10 or 3.11

> Execution role:

→ Use existing role

→ Select lambda-dynamodb-role


> Click Create function


🟢 STEP 4: Add Lambda Code :

Replace existing code with this:

==

import json

import boto3


dynamodb = boto3.resource('dynamodb')

table = dynamodb.Table('users')


def lambda_handler(event, context):


    method = event['httpMethod']


    if method == 'POST':

        body = json.loads(event['body'])

        table.put_item(Item=body)

        return {

            'statusCode': 200,

            'body': json.dumps('User created')

        }


    elif method == 'GET':

        user_id = event['queryStringParameters']['id']

        response = table.get_item(Key={'id': user_id})

        item = response.get('Item', {})

        return {

            'statusCode': 200,

            'body': json.dumps(item)

        }


    elif method == 'PUT':

        body = json.loads(event['body'])

        user_id = body['id']


        table.update_item(

            Key={'id': user_id},

            UpdateExpression="set info=:i",

            ExpressionAttributeValues={

                ':i': body['info']

            }

        )


        return {

            'statusCode': 200,

            'body': json.dumps('User updated')

        }


    elif method == 'DELETE':

        user_id = event['queryStringParameters']['id']

        table.delete_item(Key={'id': user_id})


        return {

            'statusCode': 200,

            'body': json.dumps('User deleted')

        }


    else:

        return {

            'statusCode': 400,

            'body': json.dumps('Unsupported method')

        }

==

> Click Deploy

✅ Lambda ready.


🟢 STEP 5: Create API Gateway: 


> Go to API Gateway

> Click Create API

> Choose REST API

> Click Build


> Fill:

API Name: users-api

Endpoint Type: Regional

> Click Create API


🟢 STEP 6: Create Resource:

> Click Actions → Create Resource

Resource name: users

Resource path: /users

> Click Create Resource


🟢 STEP 7: Add Methods: 


Inside /users resource:

Add these methods:

GET

POST

PUT

DELETE

For each method:

> Click Create Method

> Select method (e.g., GET)

Integration type: Lambda Function

Check: Use Lambda Proxy Integration

Choose region

Select: users-api-function

Save


> Click OK to allow permissions

==> Repeat for all 4 methods.


🟢 STEP 8: Enable CORS: 


> Select /users

> Click Actions → Enable CORS

> Confirm


🟢 STEP 9: Deploy API: 


> Click Actions → Deploy API

> Deployment stage:

New Stage

Stage name: dev

> Click Deploy


You will get:

Invoke URL like:

https://abcd1234.execute-api.us-east-1.amazonaws.com/dev


Your endpoint becomes:

https://abcd1234.execute-api.us-east-1.amazonaws.com/dev/users


🟢 STEP 10: Test Using curl :


🔹 1️⃣ Create User (POST)

# curl -X POST https://YOUR_URL/dev/users -H "Content-Type: application/json" -d '{"id":"123","name":"Alice","info":"Tester"}'

Ex: 
# shubham@7cf34de6dc20 ~ % curl -X POST https://duq42x1irl.execute-api.us-east-1.amazonaws.com/dev/users -H "Content-Type:\ application/json" -d '{"id":"123","name":"Alice","info":"Tester"}'
Expected Output: 
"User created"%



🔹 2️⃣ Get User (GET)

# curl -X GET "https://YOUR_URL/dev/users?id=123"

Ex: 
curl -X GET "https://duq42x1irl.execute-api.us-east-1.amazonaws.com/dev/users?id=123"

Expected Output: 
{"id": "123", "info": "Tester", "name": "Alice"}%

AWS console (Dynamodb Table explore) :










Browser:









🔹 3️⃣ Update User (PUT)

# curl -X PUT https://YOUR_URL/dev/users -H "Content-Type: application/json" -d '{"id":"123","info":"Updated Info"}'

Ex:
# curl -X PUT https://duq42x1irl.execute-api.us-east-1.amazonaws.com/dev/users -H "Content-Type:\ application/json" -d '{"id":"123","info":"Updated info"}'

Expected Output: 
"User updated"%

AWS console (Dynamodb Table explore) :











🔹 4️⃣ Delete User (DELETE)

# curl -X DELETE "https://YOUR_URL/dev/users?id=123"

Ex: 
# curl -X DELETE "https://duq42x1irl.execute-api.us-east-1.amazonaws.com/dev/users?id=123"

Expected Output: 
"User deleted"%


🔹 Verify deleted entry:

# curl -X GET "https://YOUR_URL/dev/users?id=123"

Ex:
curl -X GET "https://duq42x1irl.execute-api.us-east-1.amazonaws.com/dev/users?id=123"

Expected Output: 
{}%


AWS console (Dynamodb Table explore) :












Browser:








🟢 Final Testing Flow

POST → GET → PUT → GET → DELETE → GET


🎯 What You Just Built

> Fully serverless API

> No EC2

> Auto scaling

> Pay per request

> Production-grade architecture

> Cost effective and no infra to manage


======================================================




Now, lets make this more secure by WAF.

🏗 Architecture After WAF

Client → WAF → API Gateway → Lambda → DynamoDB


Web Application Firewall (WAF) is a security solution that filters, monitors, and blocks HTTP/HTTPS traffic to and from web applications, operating at Layer 7 of the OSI model. It acts as a reverse proxy, shielding applications from attacks like SQL injection, cross-site scripting (XSS), and file inclusion.

🟢 STEP 1: Create IP Set: 

> Go to AWS Console

Search → WAF & Shield

> Click IP sets

> Click Create IP set


> Fill:

Name: allowed-post-put-ips

Region: Same as API (important)

IP version: IPv4

Add addresses:

Example:

1.2.3.4/32

5.6.7.8/32


> Click Create IP set

✅ Done.


🟢 STEP 2: Create Web ACL :

> Go to Web ACLs

> Click Create web ACL

> Fill:

Name: users-api-waf

Region: Same region as API

Resource type: Regional resources

Select resource:


> Choose your API Gateway stage (example: users-api / dev)

> Click Next


🟢 STEP 3: Add Rules: 

> Click Add rules

> Choose:

➜ Add my own rules

→ Rule builder

🔹 Create Rule: Allow Specific IPs

Rule name: allow-approved-ips

Rule type: IP set

Select IP set: allowed-post-put-ips

Action: Allow

Save rule.


🔹 Add Block Rule (Default)

After adding allow rule:

Set Default action = Block

This means:

Only listed IPs allowed

All others blocked


🟢 STEP 4: Review & Create: 

> Click:

Next → Next → Create Web ACL


🎯 Now What Happens?

If request comes from:

IP : 1.2.3.4

Result : Allowed

IP : 5.6.7.8

Result : Allowed

IP: Any other

Result: 403 Forbidden

For ex:

eshubhm@7cf34de6dc20 ~ % curl -X POST https://duq42x1irl.execute-api.us-east-1.amazonaws.com/dev/users -H "Content-Type:\ application/json" -d '{"id":"123","name":"Alice","info":"Tester"}'

Expected output from non-allowed IPs:

{"message":"Forbidden"}%  


⚠ Important

> WAF works at full API level.

> If you want:

Only restrict POST and PUT

Allow GET for everyone

We need advanced rule using HTTP method condition

> WAF is NOT free.

Approx:

~$5 per Web ACL

~$1 per rule

> request charges

For learning → OK

For production → Worth it


=======================================================================
Thank you, check out more blogs for such information..!

For any queries,feel free to reach out me on shubhammore07007@gmail.com                                                                                    



Comments

Popular posts from this blog

Terraform project with AWS to build infra within seconds! (Web Ec2 with eIP)

Nginx : Setting Up Nginx with Load Balancing