APIGateway

The AWS bill shrank by 70%, but so did my DevOps dignity

Fourteen thousand dollars a month.

That number wasn’t on a spreadsheet for a new car or a down payment on a house. It was the line item from our AWS bill simply labeled “API Gateway.” It stared back at me from the screen, judging my life choices. For $14,000, you could hire a small team of actual gateway guards, probably with very cool sunglasses and earpieces. All we had was a service. An expensive, silent, and, as we would soon learn, incredibly competent service.

This is the story of how we, in a fit of brilliant financial engineering, decided to fire our expensive digital bouncer and replace it with what we thought was a cheaper, more efficient swinging saloon door. It’s a tale of triumph, disaster, sleepless nights, and the hard-won lesson that sometimes, the most expensive feature is the one you don’t realize you’re using until it’s gone.

Our grand cost-saving gamble

Every DevOps engineer has had this moment. You’re scrolling through the AWS Cost Explorer, and you spot it: a service that’s drinking your budget like it’s happy hour. For us, API Gateway was that service. Its pricing model felt… punitive. You pay per request, and you pay for the data that flows through it. It’s like paying a toll for every car and then an extra fee based on the weight of the passengers.

Then, we saw the alternative: the Application Load Balancer (ALB). The ALB was the cool, laid-back cousin. Its pricing was simple, based on capacity units. It was like paying a flat fee for an all-you-can-eat buffet instead of by the gram.

The math was so seductive it felt like we were cheating the system.

We celebrated. We patted ourselves on the back. We had slain the beast of cloud waste! The migration was smooth. Response times even improved slightly, as an ALB adds less overhead than the feature-rich API Gateway. Our architecture was simpler. We had won.

Or so we thought.

When reality crashes the party

API Gateway isn’t just a toll booth. It’s a fortress gate with a built-in, military-grade security detail you get for free. It inspects IDs, pats down suspicious characters, and keeps a strict count of who comes and goes. When we swapped it for an ALB, we essentially replaced that fortress gate with a flimsy screen door. And then we were surprised when the bugs got in.

The trouble didn’t start with a bang. It started with a whisper.

Week 1: The first unwanted visitor. A script kiddie, probably bored in their parents’ basement, decided to poke our new, undefended endpoint with a classic SQL injection probe. It was the digital equivalent of someone jiggling the handle on your front door. With API Gateway, its built-in Web Application Firewall (WAF) would have spotted the malicious pattern and drop-kicked the request into the void before it ever reached our application. With the ALB, the request sailed right through. Our application code was robust enough to reject it, but the fact that it got to knock on the application’s door at all was a bad sign. We dismissed it. “An amateur,” we scoffed.

Week 3: The client who drank too much. A bug in a third-party client integration caused it to get stuck in a loop. A very, very fast loop. It began hammering one of our endpoints with 10,000 requests per second. The servers, bless their hearts, tried to keep up. Alarms started screaming. The on-call engineer, who was attempting to have a peaceful dinner, saw his phone light up like a Christmas tree. API Gateway’s built-in rate limiting would have calmly told the misbehaving client, “You’ve had enough, buddy. Come back later.” It would have throttled the requests automatically. We had to scramble, manually blocking the IP while the system groaned under the strain.

Week 6: The full-blown apocalypse. This was it. The big one. A proper Distributed Denial-of-Service (DDoS) attack. It wasn’t sophisticated, just a tidal wave of garbage traffic from thousands of hijacked machines. Our ALB, true to its name, diligently balanced this flood of garbage across all our servers, ensuring that every single one of them was completely overwhelmed in a perfectly distributed fashion. The site went down. Hard.

The next 72 hours were a blur of caffeine, panicked Slack messages, and emergency calls with our new best friends at Cloudflare. We had saved $9,800 on our monthly bill, but we were now paying for it with our sanity and our customers’ trust.

Waking up to the real tradeoff

The hidden cost wasn’t just the emergency WAF setup or the premium support plan. It was the engineering hours. The all-nighters. The “I’m so sorry, it won’t happen again” emails to customers.

We had made a classic mistake. We looked at API Gateway’s price tag and saw a cost. We should have seen an itemized receipt for services rendered:

  • Built-in WAF: Free bouncer that stops common attacks.
  • Rate Limiting: A Free bartender who cuts off rowdy clients.
  • Request Validation: Free doorman that checks for malformed IDs (JSON).
  • Authorization: Free security guard that validates credentials (JWTs/OAuth).

An ALB does none of this. It just balances the load. That’s its only job. Expecting it to handle security is like expecting the mailman to guard your house. It’s not what he’s paid for.

Building a smarter hybrid fortress

After the fires were out and we’d all had a chance to sleep, we didn’t just switch back. That would have been too easy (and an admission of complete defeat). We came back wiser, like battle-hardened veterans of the cloud wars. We realized that not all traffic is created equal.

We landed on a hybrid solution, the architectural equivalent of having both a friendly greeter and a heavily-armed guard.

1. Let the ALB handle the easy stuff. For high-volume, low-risk traffic like serving images or tracking pixels, the ALB is perfect. It’s cheap, fast, and the security risk is minimal. Here’s how we route the “dumb” traffic in serverless.yml:

# serverless.yml
functions:
  handleMedia:
    handler: handler.alb  # A simple handler for media
    events:
      - alb:
          listenerArn: arn:aws:elasticloadbalancing:us-east-1:123456789012:listener/app/my-main-alb/a1b2c3d4e5f6a7b8
          priority: 100
          conditions:
            path: /media/*  # Any request for images, videos, etc.

2. Protect the crown jewels with API Gateway. For anything critical, user authentication, data processing, and payment endpoints, we put it back behind the fortress of API Gateway. The extra cost is a small price to pay for peace of mind.

# serverless.yml
functions:
  handleSecureData:
    handler: handler.auth  # A handler with business logic
    events:
      - httpApi:
          path: /secure/v2/{proxy+}
          method: any

3. Add the security we should have had all along. This was non-negotiable. We layered on security like a paranoid onion.

  • AWS WAF on the ALB: We now pay for a WAF to protect our “dumb” endpoints. It’s an extra cost, but cheaper than an outage.
  • Cloudflare: Sits in front of everything, providing world-class DDoS protection.
  • Custom Rate Limiting: For nuanced cases, we built our own rate limiter. A Lambda function checks a Redis cache to track request counts from specific IPs or API keys.

Here’s a conceptual Python snippet for what that Lambda might look like:

# A simplified Lambda function for rate limiting with Redis
import redis
import os

# Connect to Redis
redis_client = redis.Redis(
    host=os.environ['REDIS_HOST'], 
    port=6379, 
    db=0
)

RATE_LIMIT_THRESHOLD = 100  # requests
TIME_WINDOW_SECONDS = 60    # per minute

def lambda_handler(event, context):
    # Get an identifier, e.g., from the source IP or an API key
    client_key = event['requestContext']['identity']['sourceIp']
    
    # Increment the count for this key
    current_count = redis_client.incr(client_key)
    
    # If it's a new key, set an expiration time
    if current_count == 1:
        redis_client.expire(client_key, TIME_WINDOW_SECONDS)
    
    # Check if the limit is exceeded
    if current_count > RATE_LIMIT_THRESHOLD:
        # Return a "429 Too Many Requests" error
        return {
            "statusCode": 429,
            "body": "Rate limit exceeded. Please try again later."
        }
    
    # Otherwise, allow the request to proceed to the application
    return {
        "statusCode": 200, 
        "body": "Request allowed"
    }

The final scorecard

So, after all that drama, was it worth it? Let’s look at the final numbers.

Verdict: For us, yes, it was ultimately worth it. Our traffic profile justified the complexity. But we traded money for time and complexity. We saved cash on the AWS bill, but the initial investment in engineering hours was massive. My DevOps dignity took a hit, but it has since recovered, scarred but wiser.

Your personal sanity check

Before you follow in our footsteps, do yourself a favor and perform an audit. Don’t let a shiny, low price tag lure you onto the rocks.

1. Calculate your break-even point. First, figure out what API Gateway is costing you.

# Get your usage data from API Gateway 
aws apigateway get-usage \ --usage-plan-id your_plan_id_here \ 
   --start-date 2024-01-01 
   --end-date 2024-01-31 \ 
   --query 'items'

Then, estimate your ALB costs based on request volume.

# Get request count to estimate ALB costs
aws cloudwatch get-metric-statistics \
    --namespace AWS/ApplicationELB \
    --metric-name RequestCount \
    --dimensions Name=LoadBalancer,Value=app/my-main-alb/a1b2c3d4e5f6a7b8 \
    --start-time 2024-01-01T00:00:00Z \
    --end-time 2024-01-31T23:59:59Z \
    --period 86400 \
    --statistics Sum

2. Test your defenses (or lack thereof). Don’t wait for a real attack. Simulate one. Tools like Burp Suite or sqlmap can show you just how exposed you are.

# A simple sqlmap test against a vulnerable parameter 
sqlmap -u "https://api.yoursite.com/endpoint?id=1" --batch

If you switch to an ALB without a WAF, you might be horrified by what you find.

In the end, choosing between API Gateway and an ALB isn’t just a technical decision. It’s a business decision about risk, and one that goes far beyond the monthly bill. It’s about calculating the true Total Cost of Ownership (TCO), where the “O” includes your engineers’ time, your customers’ trust, and your sleep schedule. Are you paying with dollars on an invoice, or are you paying with 3 AM incident calls and the slow erosion of your team’s morale?

Peace of mind has a price tag. For us, we discovered its value was around $7,700 a month. We just had to get DDoS’d to learn how to read the receipt. Don’t make the same mistake. Look at your architecture not just for what it costs, but for what it protects. Because the cheapest option on paper can quickly become the most expensive one in reality.

A Step-by-Step Guide to Securely Exposing an API Gateway with AWS Services

Amazon API Gateway is a managed service that allows developers to create, publish, maintain, monitor, and secure APIs at scale. Imagine you’re building an application where different types of clients need to interact with backend services, API Gateway steps in to bridge that communication effectively. From serverless functions, like AWS Lambda, to Java microservices running on Amazon EC2, API Gateway helps unify access and security, all while optimizing scalability and cost. It enables you to streamline development by providing a standardized interface to connect different architecture components, thereby reducing complexity and improving maintainability.

In this guide, I’ll walk you through an architecture that securely exposes an API using AWS services, such as API Gateway, CloudFront, Lambda, Network Load Balancers (NLB), and others. We’ll detail each step, referencing a diagram to illustrate how all these components work together harmoniously. I hope to make this information as approachable as possible, like a conversation over coffee, where I explain concepts clearly, even if you’re new to AWS services. By the end of this guide, you should have a solid understanding of how these pieces come together to create a secure, scalable API.

Amazon API Gateway Basics

API Gateway allows you to create APIs that can serve as a front door to your backend services. Whether you have Lambda functions executing your business logic or traditional microservices running on EC2 instances, API Gateway manages traffic, secures APIs, and integrates well with AWS’s ecosystem, ensuring high availability and scalability. It acts as the centralized gateway for all the external requests coming to your application and provides a seamless way to manage those requests without overloading your backend.

API Gateway helps you manage the entire lifecycle of your API. Imagine it as the receptionist of a large office building; it controls who comes in, directs them to the appropriate room, and even handles security checks. Your backend services, whether they are Lambda functions or Java-based microservices, don’t have to worry about authentication, logging, or rate limiting, API Gateway takes care of it all. This allows your development team to focus on the core functionality without worrying about the overhead of managing all these security and operational concerns.

The AWS Architecture to Expose an API

Let’s explore the architecture itself. The diagram accompanying this article details an architecture that effectively exposes an API to the internet, utilizing multiple AWS services to create a robust and secure environment. Each component in the architecture has a specific role, and understanding these roles will help you see how they work together to create a seamless user experience.

1. Entry Point via Amazon Route 53 and CloudFront

The entry point for users starts with Amazon Route 53, which provides domain name resolution. It ensures that your custom domain is easily discoverable by mapping it to your API Gateway endpoint. Once resolved, requests are routed through Amazon CloudFront, a content delivery network (CDN) service. This adds benefits like caching and content delivery optimization, reducing latency for clients globally. The caching provided by CloudFront can significantly reduce the number of calls to your API Gateway, which also helps in cost savings by reducing the usage of downstream resources.

Think of CloudFront as a system of shortcuts. When someone tries to access your API from the other side of the globe, they hit a CloudFront edge location, which reduces travel time and ensures a faster response, saving both your API and the user precious milliseconds. In addition, CloudFront adds a layer of security by keeping certain attacks from reaching your API Gateway, since it can use geo-restriction and SSL/TLS encryption to protect your data.

2. Security with AWS WAF and API Gateway

The next layer is AWS WAF (Web Application Firewall). WAF is the gatekeeper that examines incoming traffic to ensure it’s safe. It prevents attacks, such as SQL injection or cross-site scripting, safeguarding your API from harmful traffic. WAF rules can be configured to block, allow, or count requests based on customizable conditions, such as IP addresses, HTTP headers, or request bodies.

From there, the requests arrive at API Gateway. The API Gateway processes the incoming request, applying rate limiting, authentication, and integrating seamlessly with other AWS services. Here, you’re ensuring that only authorized requests reach your backend. It also allows you to throttle requests, ensuring your backend services do not get overwhelmed during a traffic spike.

AWS IAM (Identity and Access Management) also comes into play, managing who has permissions to access specific components. IAM policies control which entities can invoke Lambda functions or communicate with the Java microservices hosted on EC2 instances. The EC2 instances must use roles defined in IAM to securely access the RDS database, ensuring that only authorized entities can connect. By assigning specific roles, you can tightly control which services or individuals can interact with the backend, minimizing the potential for unauthorized access.

3. Lambda Functions and EC2 Microservices as Backend Services

API Gateway is versatile. In this architecture, you’ll see two main paths from API Gateway:

  • AWS Lambda: If your service logic is serverless, AWS Lambda handles those operations. For example, small functions that perform specific tasks can be triggered directly. Lambda provides scalability without the hassle of managing infrastructure. Lambda is ideal for event-driven applications, where you need to process incoming requests on-demand without needing a dedicated server. Each function runs in an isolated environment, which means even if there’s an issue with one execution, it doesn’t affect others.
  • VPC Link to EC2 Instances: When dealing with microservices hosted in a VPC (Virtual Private Cloud), VPC Link is used to securely connect the API Gateway to those services. In this architecture, the VPC Link connects to a Network Load Balancer (NLB). The NLB then distributes traffic to Java microservices running on EC2 instances within a private subnet. This layer provides isolation, ensuring that the microservices aren’t directly exposed to the internet. The use of VPC Link and NLB ensures that all communication between API Gateway and EC2 instances remains within the secure boundaries of the AWS network, enhancing security.

Think of the NLB as the traffic officer. It receives all the cars (requests) from the VPC Link and directs them to one of the EC2 instances (Java microservices), making sure none of them get overwhelmed. This ensures that your backend can handle requests efficiently, even during peak load times, by spreading the requests across multiple instances.

4. A RDS Database for Data Persistence

The backend services running on EC2 interact with an Amazon RDS (Relational Database Service) instance. The RDS instance sits within another private subnet in the VPC, providing a managed database solution that scales according to the demands of your application. It’s isolated from the public internet, with access controlled strictly by security groups to ensure that only your EC2 microservices can communicate with it. The subnet is private, meaning it has no direct route to the internet, and only the specific port used by the database (typically port 3306 for MySQL, for example) is open to allow inbound traffic from authorized EC2 instances. This minimizes the risk of unauthorized access or potential attacks.

Moreover, the IAM roles assigned to the EC2 instances ensure that each request made to the RDS database is authenticated securely. The controlled access combined with the private subnet adds a defense-in-depth approach, significantly enhancing the security posture of the application. This setup means that even if an attacker were to gain access to other parts of the infrastructure, reaching the RDS database would still be extremely challenging due to the multiple layers of protection.

5. Monitoring with AWS CloudWatch

Lastly, everything needs to be monitored. AWS CloudWatch is used to track metrics and log information across API Gateway, Lambda, and the EC2 instances. CloudWatch helps you understand how the system is behaving, allows you to define alarms for anything out of the ordinary, and ensures that you always have insight into your services’ health. By setting up CloudWatch alarms, you can automatically get notifications if something isn’t performing as expected, allowing you to respond quickly and ensure high availability.

Security groups add a further layer of control, dictating what traffic is allowed in and out of the private subnets. These configurations ensure that only legitimate requests are allowed to reach the EC2 instances or interact with the RDS database. By fine-tuning the security group rules, you can restrict access further, allowing only specific IP ranges or VPC endpoints to communicate with your services.

Final Thoughts and Recommendations

Here are two important considerations to keep in mind as you design your architecture:

  • Clarifying the Connection Between API Gateway and VPC Link: It’s essential to understand that the connection from API Gateway to VPC Link is designed specifically for securely communicating with services residing inside the VPC. This is different from invoking Lambda functions directly, which are handled outside the VPC context. 
  • Balancing Security and Simplicity: The architecture presented here represents a foundational approach to securely exposing an API. It’s valuable to highlight additional security options, such as implementing Network ACLs (NACLs) or creating more granular Security Groups, as a way to enhance the balance between accessibility and security. This approach allows you to keep the initial design straightforward while providing paths for more sophisticated security as requirements evolve.

I hope this guide has demystified the architecture for you. Think of it like a well-oiled machine or even a kitchen during the dinner rush. Every part has a job, API Gateway is the head chef calling out orders, CloudFront is like the waiter running dishes out to customers quickly, and WAF is the security guard keeping everything safe. When each part knows its role and plays it well, the whole restaurant runs smoothly. Understanding these concepts will not only help you build better applications but will also give you the confidence to scale and secure your services, just like a seasoned chef confidently managing a busy kitchen.

Let’s Party, Understanding Serverless Architecture on AWS

Imagine you’re throwing a big party, but instead of doing all the work yourself, you have a team of helpers who each specialize in different tasks. That’s what we’re doing with serverless architecture on AWS, we’re organizing a digital party where each AWS service is like a specialized helper.

Let’s start with AWS Lambda. Think of Lambda as your multitasking friend who’s always ready to help. Lambda springs into action whenever something happens, like a guest arriving (an API request) or someone bringing a dish (uploading a file). It doesn’t need to be told what to do beforehand; it just responds when needed. This is great because you don’t have to keep this friend around always, only when there’s work to be done.

Now, let’s talk about API Gateway. This is like your doorman. It greets your guests (user requests), checks their invitations (authenticates them), and directs them to the right place in your party (routes the requests). It works closely with Lambda to ensure every guest gets the right experience.

For storing information, we have DynamoDB. Imagine this as a super-efficient filing cabinet that can hold and retrieve any piece of information instantly, no matter how many guests are at your party. It doesn’t matter if you have 10 guests or 10,000; this filing cabinet works just as fast.

Then there’s S3, which is like a magical closet. You can store anything in it, coats, party supplies, even leftover food, and it never runs out of space. Plus, it can alert Lambda whenever something new is put inside, so you can react to new items immediately.

For communication, we use SNS and SQS. Think of SNS as a loudspeaker system that can make announcements to everyone at once. SQS, on the other hand, is more like a ticket system at a delicatessen counter. It makes sure tasks are handled in an orderly fashion, even if a lot of requests come in at once.

Lastly, we have Step Functions. This is like your party planner who knows the sequence of events and makes sure everything happens in the right order. If something goes wrong, like the cake not arriving on time, the planner knows how to adjust and keep the party going.

Now, let’s see how all these helpers work together to throw an amazing party, or in our case, build a photo-sharing app:

  1. When a guest (user) wants to share a photo, they hand it to the doorman (API Gateway).
  2. The doorman calls over the multitasking friend (Lambda) to handle the photo.
  3. This friend puts the photo in the magical closet (S3).
  4. As soon as the photo is in the closet, S3 alerts another multitasking friend (Lambda) to create smaller versions of the photo (thumbnails).
  5. But what if lots of guests are sharing photos at once? That’s where our ticket system (SQS) comes in. It gives each photo a ticket and puts them in an orderly line.
  6. Our multitasking friends (Lambda functions) take photos from this line one by one, making sure no photo is left unprocessed, even during a photo-sharing frenzy.
  7. Information about each processed photo is written down and filed in the super-efficient cabinet (DynamoDB).
  8. The loudspeaker (SNS) announces to interested parties that a new photo has arrived.
  9. If there’s more to be done with the photo, like adding filters, the party planner (Step Functions) coordinates these additional steps.

The beauty of this setup is that each helper does their job independently. If suddenly 100 guests arrive at once, you don’t need to panic and hire more help. Your existing team of AWS services can handle it, expanding their capacity as needed.

This serverless approach means you’re not paying for helpers to stand around when there’s no work to do. You only pay for the actual work done, making it very cost-effective. Plus, you don’t have to worry about managing these helpers or their equipment, AWS takes care of all that for you.

In essence, serverless architecture on AWS is about having a smart, flexible, and efficient team that can handle any party, big or small, without needing to micromanage. It lets you focus on making your app amazing, while AWS ensures everything runs smoothly behind the scenes.

In conclusion, understanding how to integrate AWS services is crucial for building effective serverless architectures. By leveraging the strengths of Lambda, API Gateway, DynamoDB, S3, SNS, SQS, and Step Functions, you can create robust applications that meet your business needs with minimal operational overhead. And just like that, you can enjoy the party with your guests, knowing everything is running smoothly in the background! 🥳🎉