HHardikShah
    Contact Me

    Secure Serverless Platform for a Human Rights NGO

    Built a serverless AWS platform for a human rights NGO: WAF and API Gateway in front of VPC-attached Lambda functions, with Cognito sign-in, RDS, DynamoDB and queued email.

    Published · Updated

    1 year
    Timeline
    18
    Technologies
    3
    Key Results
    Multi-AZ
    Resilience
    Secure Serverless Platform for a Human Rights NGO

    Context & Pain Points

    The organisation works on labour rights and human trafficking, so the people in its records are often the ones most at risk if those records leak. The platform had to hold personal details, sign-in identities and case information, and every one of those is worth protecting more carefully than an ordinary web app would. The team running it was small and the budget was a nonprofit's. That ruled out a fleet of always-on servers that someone would have to patch, size and watch. Usage also came in bursts, around field reporting rounds and campaigns, with long quiet stretches between them. Paying for peak capacity all year would have spent money the organisation needed for its actual work. Because the data was sensitive, it had to stay off the public internet wherever the architecture allowed. Someone also had to hear quickly if anything in the account started to look wrong.

    What We Had To Solve

    • Keeping sensitive records off the public internet while running serverless. Lambda is easiest to run outside a VPC, but then every call to a database or bucket leaves the private network. The functions needed private paths to RDS, DynamoDB and S3 without giving up the serverless model.
    • Paying for real use, not for peak. Traffic arrived in bursts around field reporting rounds, and an always-on fleet sized for those bursts would have sat idle most of the year on a nonprofit budget.
    • Running a Django application without managing servers. The existing code was a Django app, and rewriting it as separate microservices was not a good use of a small team's time.
    • Handling sign-up and identity safely. Passwords, verification and account recovery are easy to get wrong in custom code, and a mistake there exposes exactly the people the organisation protects.
    • Knowing quickly when something goes wrong. A small team cannot watch logs all day, so findings had to reach them instead of waiting to be found.

    How We Built It

    • Attached the Lambda functions to private application subnets in two Availability Zones. RDS sits in an isolated subnet with no internet route, and DynamoDB and S3 are reached through gateway VPC endpoints. Only outbound calls that genuinely need the internet leave through a NAT gateway.
    • Put AWS WAF in front of an API Gateway REST API, so requests are filtered before any function runs. The public entry point is a managed service rather than a server.
    • Ran the Django application as a Lambda function behind API Gateway, alongside small single-purpose functions for user management, user profiles and email.
    • Handed sign-up, sign-in and account recovery to an Amazon Cognito user pool, so password storage and verification never live in application code.
    • Moved email off the request path. A sign-up publishes to an SQS queue, an email function consumes it and sends through SES, and a slow mail provider no longer slows a sign-up. EventBridge triggers scheduled work and SNS sends notifications out.
    • Turned on AWS Config, GuardDuty, Security Hub and Macie across the account, with Macie looking for personal data in S3. Function logs go to CloudWatch.

    Outcomes That Mattered

    Pay for Use

    Lambda and API Gateway run only when a request arrives, so compute cost follows real usage instead of being sized for the busiest week of the year.

    Private Data Paths

    Functions reach RDS from inside the VPC and DynamoDB and S3 through gateway endpoints, so sensitive records do not cross the public internet.

    Continuous Detection

    GuardDuty, Security Hub, AWS Config and Macie watch the account, so a finding reaches the team instead of waiting in a log.

    Outcome

    The platform runs on AWS in a VPC that spans two Availability Zones. Requests pass AWS WAF first, then an API Gateway REST API, which invokes Lambda functions attached to private application subnets in both zones. A Django application runs as one function and keeps its data in Amazon RDS, inside an isolated database subnet with no route to the internet. Sign-up and sign-in go through a user management function backed by an Amazon Cognito user pool. User profiles live in a DynamoDB table, and documents live in S3, and the functions reach both through gateway VPC endpoints instead of the public internet. A new sign-up publishes a message to an SQS queue, which triggers an email function that sends through Amazon SES. EventBridge drives scheduled work, and SNS carries notifications out. The functions log to CloudWatch, and the account runs AWS Config, GuardDuty, Security Hub and Macie.