Securing API Gateway with AWS Lambda Authorizers

Securing API Gateway with AWS Lambda Authorizers

APIs are the backbone of fitness apps, allowing seamless communication between the client, server, and external services. However, exposing APIs to unauthorized access can lead to data breaches or abuse. For this reason, I need to point out that securing your API Gateway is essential. AWS Lambda Authorizers provide a robust mechanism for verifying and managing user authentication tokens, ensuring only authorized requests access your backend.

In this article, we’ll walk through setting up a Lambda authorizer to secure API Gateway, managing API keys securely, and automating the configuration using Terraform.


Why Use Lambda Authorizers?

Lambda Authorizers enable fine-grained access control by letting you verify requests before they reach your backend. For a fitness app, this ensures:

  • Secure API Access: Protecting user data and sensitive operations.
  • Customizable Authentication: You control how authentication tokens (e.g., API keys) are validated.
  • Scalability: AWS automatically scales Lambda authorizers with API Gateway traffic.


Setting Up the Lambda Authorizer

Here’s the Lambda function you’ve provided, which checks the validity of an API key stored securely in AWS Secrets Manager:

Lambda Authorizer Implementation

import json
import logging
import os

import boto3

logger = logging.getLogger()
logger.setLevel(logging.INFO)

secrets_manager = boto3.client("secretsmanager")


def get_secret(secret_name):
    try:
        response = secrets_manager.get_secret_value(SecretId=secret_name)
        secret = json.loads(response["SecretString"])
        return secret["API_KEY"]
    except Exception as e:
        logger.error(f"Error fetching secret: {e}")
        raise ValueError("Failed to retrieve API key secret")


def lambda_handler(event, context):
    logger.info("Received event: %s", json.dumps(event))

    try:
        secret_name = os.environ.get("API_KEY_SECRET")
        if not secret_name:
            logger.error("Missing environment variable: API_KEY_SECRET")
            raise ValueError("API_KEY_SECRET environment variable is not set")

        api_key_secret = get_secret(secret_name)

        headers = event.get("headers", {})
        client_key = headers.get("x-api-key")

        if client_key and client_key.strip() == api_key_secret.strip():
            logger.info("Authorization succeeded")
            return {"isAuthorized": True}
        else:
            logger.info("Authorization failed")
            return {"isAuthorized": False}
    except Exception as e:
        logger.exception("Unexpected error in authorizer")
        return {"isAuthorized": False}        

How It Works

  1. Fetching Secrets: The function retrieves the API key securely stored in AWS Secrets Manager.
  2. Header Validation: It checks the incoming x-api-key header against the stored API key.
  3. Authorization Decision: If the keys match, the request is authorized; otherwise, it’s rejected.


Configuring the Authorizer in API Gateway Using Terraform

Here’s how to automate the setup of the Lambda authorizer and its integration with API Gateway:

Terraform Configuration

Lambda Function for Authorizer: Define the Lambda function for the authorizer:

resource "aws_lambda_function" "authorizer" {
  filename         = "authorizer.zip"
  function_name    = "${var.environment}_api_authorizer"
  role             = aws_iam_role.lambda_execution_role.arn
  handler          = "lambda_function.lambda_handler"
  runtime          = "python3.9"
  environment {
    variables = {
      API_KEY_SECRET = "YourSecretName"
    }
  }
}        

API Gateway Integration: Attach the Lambda authorizer to API Gateway:

resource "aws_apigateway_rest_api" "fitness_api" {
  name = "FitnessAPI"
}

resource "aws_apigateway_authorizer" "lambda_authorizer" {
  name                    = "APIKeyAuthorizer"
  type                    = "REQUEST"
  rest_api_id             = aws_apigateway_rest_api.fitness_api.id
  authorizer_uri          = "arn:aws:apigateway:${var.region}:lambda:path/2015-03-31/functions/${aws_lambda_function.authorizer.arn}/invocations"
  identity_source         = "method.request.header.x-api-key"
}

resource "aws_apigateway_method" "secure_method" {
  rest_api_id   = aws_apigateway_rest_api.fitness_api.id
  resource_id   = aws_apigateway_resource.resource.id
  http_method   = "GET"
  authorization = "CUSTOM"
  authorizer_id = aws_apigateway_authorizer.lambda_authorizer.id
}        

Grant Permissions to API Gateway: Allow API Gateway to invoke the Lambda authorizer:

resource "aws_lambda_permission" "api_gateway_invoke" {
  statement_id  = "AllowExecutionFromAPIGateway"
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.authorizer.function_name
  principal     = "apigateway.amazonaws.com"
}        

Authorization Flow

Here’s how the process works:

  1. A client requests the API Gateway with the x-api-key header.
  2. API Gateway invokes the Lambda authorizer.
  3. The authorizer validates the key against the Secrets Manager.
  4. If valid, the request is forwarded to the backend; otherwise, it is denied.


Visuals

Sequence Diagram

Client → API Gateway → Lambda Authorizer → AWS Secrets Manager → API Gateway → Backend        

Logs Showing Token Validation

Logs from the Lambda function for successful and failed authorizations:

  • Successful Authorization:

INFO: Received event: {...}
INFO: Authorization succeeded        

  • Failed Authorization:

INFO: Received event: {...}
INFO: Authorization failed        

Implementing a Lambda authorizer ensures that only authorized clients can access your fitness app's API. Combining API Gateway, Secrets Manager, and Terraform provides a scalable, secure, and automated solution. This approach protects user data while offering the flexibility to manage authentication dynamically.

great overview

回复

要查看或添加评论,请登录

Todd Bernson的更多文章

社区洞察

其他会员也浏览了