100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Multi-Cloud Architecture & Serverless
60 minadvanced

AWS serverless backend — Lambda, API GW and DynamoDB Global Tables

This exercise builds Milestone 1 of the capstone: the AWS serverless backend serving IPL scorecard data from two active-active regions. You will deploy Lambda, API Gateway HTTP API, DynamoDB Global Tables, CloudFront with WAF, and Route 53 latency routing as a complete integrated stack using AWS SAM. Each step builds on the previous, and the milestone validation at the end confirms all components work together before you proceed to Milestone 2.

Analogy🏏Cricket
🏏 Think of it like cricket: In Test cricket, the ICC publishes playing conditions — governing over rates, DRS quotas, pitch inspection protocols, and player conduct — that both captains sign before the first session, whether the match is at Lord’s, the MCG, or Eden Gardens. Just as the playing conditions give umpires a single authoritative standard so every ruling references the same document rather than personal judgement, the Well-Architected Framework gives architects a shared evaluation language so every workload is measured against the same six pillars rather than each engineer’s intuition. Just as a team posting a slow over rate incurs penalties regardless of their score, a workload with Security or Reliability gaps carries structural risk regardless of how quickly it shipped. Just as every specialist role — opener, keeper, tail — has defined performance expectations against which selectors evaluate each player, every workload component is evaluated against pillar-specific best-practice questions. This reveals why the framework must precede any advanced architectural decision: a shared, evidence-based standard transforms subjective trade-offs into structured, auditable risk assessments that hold across teams, accounts, and regions.

The architecture you build in this exercise is the same architecture deployed to serve real-time cricket statistics at scale. Lambda handles API requests, DynamoDB Global Tables provides sub-second cross-region data replication, CloudFront caches scorecards at the edge reducing Lambda invocations by 80%, and Route 53 latency routing automatically directs Asia-Pacific fans to the closest healthy region. The GitHub Actions WIF deployment pipeline ensures no GCP or AWS credentials are stored in the repository.

Work through each step in sequence. Each step includes a reference code block and a validation command. Run the validation command after completing each step before proceeding to the next. If a validation fails, debug the current step before advancing: errors introduced in an early step compound into confusing multi-layer failures in later steps. The milestone validation at the end of the exercise confirms all components work together end-to-end.

Scenario

You are the lead architect for the IPL Scorecard Platform’s AWS infrastructure. The platform must be live before the IPL season starts in 6 weeks. The engineering team has agreed on the architecture from the project brief. Your role is to implement Milestone 1: the AWS serverless backend with active-active multi-region deployment, CloudFront edge caching with WAF, and Route 53 failover routing.

Analogy🏏Cricket
🏏 Think of it like cricket: this resize scenario is like the media crew on a busy match day handling a predictable flow of highlight stills with sudden bursts during a collapse. Just as the IPL media team uploads about 500 images per match day, each 8 MB, needing broadcast, web, and mobile variants within 30 seconds, the crew shoots a steady stream of key moments that must hit the big screen, website, and app almost immediately. Just as the pipeline must absorb occasional bursts of 50 to 100 images when wickets tumble in a cluster, the crew faces a flurry of must-capture frames during a dramatic middle-order collapse and cannot drop any. The 30-second processing target is like the rule that a replay must reach the screen before the next ball is bowled. The payoff: like a crew sized for the steady rhythm yet ready for a sudden rush, the design must meet the everyday load cheaply while scaling instantly through a burst without losing a single frame.

The team has already provisioned the DynamoDB table schema and seeded test data for the IPL 2024 Final. Your implementation starts with the Lambda function and works outward through API Gateway, CloudFront, and Route 53. The GitHub Actions pipeline will deploy changes to both Mumbai and Singapore simultaneously on every merge to main. You must configure the WIF authentication for the deployment pipeline as the final step.

Step 1 — SAM Template and Lambda Deployment

Write the SAM template defining the Lambda function with the IPL scorecard handler, the API Gateway HTTP API with JWT authorisation, and the DynamoDB table name as an environment variable. Deploy to ap-south-1 first and validate that the API responds with match data before deploying the Singapore replica. Use the sam deploy command with an explicit stack name that encodes the region to distinguish the two regional stacks.

Analogy🏏Cricket
🏏 Think of it like cricket: A touring team proves its game plan at the home ground first and only then replicates the identical setup at the second venue, labelling each ground's kit clearly so nothing gets mixed up. Just as you would validate the eleven at your primary ground before shipping the same plan abroad, this step deploys the SAM-defined Lambda handler, the API Gateway HTTP API with JWT authorisation, and the DynamoDB table name as an environment variable to ap-south-1 first, confirming the API returns match data before deploying the Singapore replica. Just as each venue's equipment cases are stencilled with the ground name to keep the two stacks distinct, you use a stack name that encodes the region — ipl-scorecard-ap-south-1 versus ipl-scorecard-ap-southeast-1. Just as the away setup mirrors the tested home template exactly, the second region reuses the same SAM template. The payoff: validating one region before replicating it, with region-encoded stack names, prevents a broken configuration from silently propagating to both regions at once.
python
# sam-template.yaml — Milestone 1 SAM template

sam_template = '''
AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31

Parameters:
  TableName:
    Type: String
    Default: ipl-scores-global
  Environment:
    Type: String
    AllowedValues: [prod, staging]
    Default: prod

Globals:
  Function:
    Runtime: python3.11
    Tracing: Active
    Environment:
      Variables:
        TABLE_NAME: !Ref TableName
        ENVIRONMENT: !Ref Environment
    Tags:
      team: scorecard-api
      environment: !Ref Environment
      cost-centre: ipl-platform

Resources:
  IplScorecardFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub ipl-scorecard-${Environment}
      CodeUri: src/
      Handler: scorecard.handler
      MemorySize: 512
      Timeout: 10
      Policies:
        - DynamoDBReadPolicy:
            TableName: !Ref TableName
      Events:
        GetScoreById:
          Type: HttpApi
          Properties:
            Path: /api/scores/{matchId}
            Method: GET
            ApiId: !Ref IplHttpApi

  IplHttpApi:
    Type: AWS::Serverless::HttpApi
    Properties:
      StageName: prod
      CorsConfiguration:
        AllowOrigins: ["*"]
        AllowMethods: [GET, OPTIONS]

Outputs:
  ApiEndpoint:
    Value: !Sub https://${IplHttpApi}.execute-api.${AWS::Region}.amazonaws.com/prod
    Export:
      Name: !Sub IplApiEndpoint-${AWS::Region}
  LambdaArn:
    Value: !GetAtt IplScorecardFunction.Arn
    Export:
      Name: !Sub IplLambdaArn-${AWS::Region}
'''

print('Deploy to Mumbai:  sam deploy --stack-name ipl-scorecard-ap-south-1    --region ap-south-1')
print('Deploy to Singapore: sam deploy --stack-name ipl-scorecard-ap-southeast-1 --region ap-southeast-1')
print('Validate: curl https://<api-id>.execute-api.ap-south-1.amazonaws.com/prod/api/scores/IPL2024FINAL')
print('Expected: [{"matchId": "IPL2024FINAL", "battingTeam": "KolkataKnightRiders", ...}]')

Step 2 — DynamoDB Global Tables

Enable DynamoDB Global Tables to replicate the ipl-scores-global table between ap-south-1 and ap-southeast-1. The table must have DynamoDB Streams enabled with NEW_AND_OLD_IMAGES before adding the Singapore replica. Verify replication is active by writing a test item in Mumbai and confirming it appears in Singapore within 5 seconds. Record the replication latency for the project brief’s RPO calculation.

Analogy🏏Cricket
🏏 Think of it like cricket: Two co-captains sharing live command of a match need an instant, faithful relay of every call between them — and that relay only works if a running commentary of each decision is being broadcast in the first place. Just as the relay depends on that live commentary feed existing, DynamoDB Global Tables replicate through DynamoDB Streams, so the table must have Streams enabled with NEW_AND_OLD_IMAGES before the Singapore replica can be added. Just as you would test the relay by making a call at one end and confirming it reaches the other within a heartbeat, this step writes a test item in Mumbai and confirms it appears in Singapore within 5 seconds. Just as a team notes exactly how fast the relay is so it knows how much could be lost if one captain drops out, you record the replication latency to feed the project brief's RPO calculation. The payoff: verified sub-second cross-region replication with a measured latency is what lets the active-active design promise that a regional loss costs at most a few seconds of data.
python
import boto3, json, time

ddb_mum = boto3.client('dynamodb', region_name='ap-south-1')
ddb_sin = boto3.client('dynamodb', region_name='ap-southeast-1')
table_r = boto3.resource('dynamodb', region_name='ap-south-1').Table('ipl-scores-global')

# Enable streams if not already enabled (required for Global Tables).
ddb_mum.update_table(
    TableName='ipl-scores-global',
    StreamSpecification={'StreamEnabled': True, 'StreamViewType': 'NEW_AND_OLD_IMAGES'},
)
print('Streams enabled. Adding Singapore replica...')

# Add Singapore as a Global Tables replica.
ddb_mum.update_table(
    TableName='ipl-scores-global',
    ReplicaUpdates=[{'Create': {'RegionName': 'ap-southeast-1'}}],
)

# Wait for replication to be active (typically 2-5 minutes).
print('Waiting for replica to become ACTIVE (this takes 2-5 minutes)...')
while True:
    desc = ddb_mum.describe_table(TableName='ipl-scores-global')['Table']
    replicas = desc.get('Replicas', [])
    sg_replica = next((r for r in replicas if r['RegionName']=='ap-southeast-1'), None)
    if sg_replica and sg_replica['ReplicaStatus'] == 'ACTIVE':
        print('Singapore replica is ACTIVE.')
        break
    time.sleep(30)

# Measure replication latency.
test_item = {'matchId': 'REPLICATION-TEST', 'inningsNum': 0, 'ts': int(time.time())}
table_r.put_item(Item=test_item)
write_time = time.time()

table_sg = boto3.resource('dynamodb', region_name='ap-southeast-1').Table('ipl-scores-global')
for _ in range(20):
    result = table_sg.get_item(Key={'matchId': 'REPLICATION-TEST', 'inningsNum': 0})
    if 'Item' in result:
        print(f'Replication latency: {time.time()-write_time:.2f}s')
        table_r.delete_item(Key={'matchId': 'REPLICATION-TEST', 'inningsNum': 0})
        break
    time.sleep(0.5)

Step 3 — CloudFront Distribution and WAF

Deploy a CloudFront distribution with two cache behaviours: /api/scores/* with a 3-second TTL (live scores change every delivery), and /static/* with an 86,400-second TTL. Attach a WAF WebACL with the AWS Managed Rules Common Rule Set and a rate limit rule blocking IPs that exceed 1,000 requests per 5 minutes. Configure the CloudFront distribution to use both API Gateway endpoints as origin group members, with Mumbai as primary and Singapore as failover.

Analogy🏏Cricket
🏏 Think of it like cricket: A stadium tailors how long it trusts different information and screens the crowd at the gate. Just as the live score on the giant screen must refresh almost every ball while the printed match programme stays valid all day, CloudFront caches /api/scores/* for just 3 seconds — live scores change every delivery — but /static/* for a full day at 86,400 seconds. Just as the entrance security screens every arrival for known trouble and turns away anyone hammering the gate too many times, the WAF WebACL applies the AWS Managed Common Rule Set and a rate-limit rule blocking any IP exceeding 1,000 requests per 5 minutes. Just as the fixture names a main ground with a reserve venue on standby, the CloudFront origin group uses Mumbai as primary and Singapore as failover. The payoff: content-appropriate caching cuts origin load and latency, the WAF absorbs attacks at the edge before they reach Lambda, and origin failover keeps scores flowing even if the primary region's API stops responding.
python
import boto3

cf    = boto3.client('cloudfront')
wafv2 = boto3.client('wafv2', region_name='us-east-1')  # WAF for CF must be us-east-1

# Create WAF WebACL with AWS Managed Rules + rate limit.
web_acl = wafv2.create_web_acl(
    Name='ipl-scorecard-waf',
    Scope='CLOUDFRONT',
    DefaultAction={'Allow': {}},
    Rules=[
        {
            'Name': 'AWSManagedRulesCommonRuleSet', 'Priority': 1,
            'OverrideAction': {'None': {}},
            'Statement': {'ManagedRuleGroupStatement': {
                'VendorName': 'AWS', 'Name': 'AWSManagedRulesCommonRuleSet'}},
            'VisibilityConfig': {'SampledRequestsEnabled': True,
                                  'CloudWatchMetricsEnabled': True,
                                  'MetricName': 'CommonRuleSet'},
        },
        {
            'Name': 'IPLRateLimitRule', 'Priority': 2,
            'Action': {'Block': {}},
            'Statement': {'RateBasedStatement': {
                'Limit': 1000, 'AggregateKeyType': 'IP',
                'EvaluationWindowSec': 300}},
            'VisibilityConfig': {'SampledRequestsEnabled': True,
                                  'CloudWatchMetricsEnabled': True,
                                  'MetricName': 'RateLimit'},
        },
    ],
    VisibilityConfig={'SampledRequestsEnabled': True,
                       'CloudWatchMetricsEnabled': True,
                       'MetricName': 'IPLScorecardWAF'},
)
waf_arn = web_acl['Summary']['ARN']
print(f'WAF WebACL: {waf_arn}')

# CloudFront distribution with origin group (Mumbai primary, Singapore failover).
# Full distribution config omitted for brevity; key settings shown:
print('CloudFront distribution config key settings:')
print('  Origins: ap-south-1 API GW (primary) + ap-southeast-1 API GW (failover)')
print('  Default cache behaviour: /api/scores/* TTL=3s, WAF attached')
print('  Cache behaviour: /static/* TTL=86400s')
print('  ViewerCertificate: ACM certificate for api.ipl.srihayavadhana.in')
print(f'  WebACLId: {waf_arn}')

Step 4 — Route 53 Failover Configuration

Configure Route 53 latency routing records for api.ipl.srihayavadhana.in pointing to the CloudFront distribution (which itself handles origin failover between Mumbai and Singapore). Create calculated health checks for each AWS region using the composite alarm pattern from Module 5: a region is considered unhealthy only when the API error rate AND the DynamoDB replication lag BOTH exceed thresholds simultaneously, preventing false positive failovers.

Analogy🏏Cricket
🏏 Think of it like cricket: A seasoned match referee does not abandon a game on a single ambiguous signal — he calls it off only when two independent conditions agree, say the light meter AND the umpires both confirming play is unsafe, so a lone flickering reading never triggers a needless stoppage. Just as that two-signal rule prevents false abandonments, this step's Route 53 uses calculated health checks built on a composite alarm: a region is judged unhealthy only when the API error rate AND the DynamoDB replication lag both breach their thresholds at once. Just as fans are simply directed to whichever ground is nearest and open, Route 53 latency routing sends each user to the CloudFront distribution, which itself handles Mumbai-Singapore origin failover. Just as one bad reading alone should never move a match, one metric spiking alone should never force a failover. The payoff: composite, two-condition health checks make regional failover trigger on genuine outages rather than transient blips, avoiding disruptive false-positive failovers during a live match.

Step 5 — GitHub Actions WIF Deployment Pipeline

Configure the GitHub Actions deployment pipeline using Workload Identity Federation to deploy to both AWS regions without storing credentials. Create a WIF OIDC provider in AWS IAM for GitHub Actions, configure the trust policy on the deployment role, and write the GitHub Actions workflow file. The deployment should run sam deploy for both regions in parallel to minimise deployment time, with the Singapore deployment depending on the Mumbai deployment’s success.

Analogy🏏Cricket
🏏 Think of it like cricket: The touring staff deploy identical training setups at both grounds using match-day accreditation verified on the spot, never a permanent pass that could be copied — and the away ground is only set up once the home ground's setup has succeeded. Just as accreditation is checked against the official register rather than a stored key, this step configures a WIF OIDC provider in AWS IAM for GitHub Actions and a trust policy on the deployment role, so the pipeline assumes the role via a short-lived OIDC token with no credentials stored in the repository. Just as both grounds are prepared in parallel to save time, the workflow runs sam deploy for both regions concurrently. Just as the away setup waits on the home setup passing first, the Singapore job depends on the Mumbai deployment succeeding. The payoff: keyless, parallel, dependency-ordered deployment to both regions — fast, credential-free, and safe against pushing a broken build to the second region before the first is confirmed good.
python
# GitHub Actions workflow: deploy to both AWS regions using WIF.
gh_workflow = '''
name: Deploy IPL Scorecard API
on:
  push:
    branches: [main]

jobs:
  deploy-mumbai:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    steps:
      - uses: actions/checkout@v4
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::111111:role/ipl-github-deploy-role
          aws-region: ap-south-1
          role-session-name: GithubActionsMumbai
      - uses: aws-actions/setup-sam@v2
      - run: sam deploy
              --stack-name ipl-scorecard-ap-south-1
              --region ap-south-1
              --no-confirm-changeset
              --no-fail-on-empty-changeset

  deploy-singapore:
    needs: deploy-mumbai   # deploy Singapore only after Mumbai succeeds
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    steps:
      - uses: actions/checkout@v4
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::111111:role/ipl-github-deploy-role
          aws-region: ap-southeast-1
          role-session-name: GithubActionsSingapore
      - uses: aws-actions/setup-sam@v2
      - run: sam deploy
              --stack-name ipl-scorecard-ap-southeast-1
              --region ap-southeast-1
              --no-confirm-changeset
              --no-fail-on-empty-changeset
'''
print('GitHub Actions workflow configured for WIF deployment to both regions.')

Milestone 1 Validation

  • GET https://api.ipl.srihayavadhana.in/api/scores/IPL2024FINAL returns HTTP 200 with innings data and X-Served-By: aws-ap-south-1 header.
  • DynamoDB console shows ipl-scores-global table with an ap-southeast-1 ACTIVE replica and replication latency under 2 seconds for test writes.
  • CloudFront console shows the distribution with WAF attached, cache hit rate above 70% after 10 minutes of synthetic traffic, and origin failover configured.
  • Route 53 shows two latency routing records with health checks both in Healthy state.
  • GitHub Actions workflow run shows both deploy-mumbai and deploy-singapore jobs completing successfully with aws-actions/configure-aws-credentials using OIDC (no stored credentials).
  • Failover drill: stopping the Mumbai API Gateway returns Singapore responses within 90 seconds as confirmed by repeated dig queries.

Warning: The SAM deploy for Singapore must use the same table name (ipl-scores-global) that was used for the Mumbai stack. If the Singapore stack creates a new table with a different name, it will not be part of the Global Table and data will not replicate. The DynamoDB Global Table is a single resource spanning multiple regions; do not create a separate table per region — add the Singapore region as a replica of the existing Mumbai table.

Lesson 37 of 40
0% complete