Skip to main content

A CDK construct that fronts an HTTP API with a CloudFront distribution and protects it with AWS WAF.

Project description

WAF HTTP API

A CDK construct that fronts an HTTP API with a CloudFront distribution and protects it with AWS WAF.

npm version PyPI version

Features

  • Enhanced Security: Protects your HTTP API with AWS WAF rules
  • Global CDN: Fronts your API with CloudFront for improved performance and availability
  • Custom Domains: Support for custom domains with automatic SSL certificate management (requires hosted zone for DNS validation)
  • Automatic DNS Records: Automatically creates Route 53 A and AAAA records for custom domains
  • Origin Verification: Adds a secret header to ensure requests come through CloudFront
  • Customizable: Use default WAF rules or provide your own custom rules
  • Easy Integration: Simple to add to existing AWS CDK stacks

Installation

TypeScript/JavaScript

npm install waf-http-api

Python

pip install waf-http-api

Examples

Complete working examples demonstrating the usage of waf-http-api can be found in the example/ directory:

  • TypeScript Example: Full CDK application with Node.js 22 Lambda, comprehensive tests, and deployment scripts
  • Python Example: Complete CDK application with Python 3.12 Lambda, pytest test suite, and development tools

Both examples include:

  • ✅ Complete CDK stacks using the WafHttpApi construct
  • ✅ Lambda functions with origin verification
  • ✅ HTTP API Gateway with multiple routes
  • ✅ Comprehensive test suites
  • ✅ Build and deployment scripts
  • ✅ Detailed documentation

These examples serve as practical references for implementing WAF-protected HTTP APIs in production environments.

Usage

Basic Usage

This example shows how to protect an HTTP API with WAF and CloudFront:

import { Stack, StackProps } from "aws-cdk-lib";
import { HttpApi, HttpMethod } from "aws-cdk-lib/aws-apigatewayv2";
import { HttpLambdaIntegration } from "aws-cdk-lib/aws-apigatewayv2-integrations";
import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";
import { Runtime } from "aws-cdk-lib/aws-lambda";
import { WafHttpApi } from "waf-http-api";

class MyStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    const myLambda = new NodejsFunction(this, "MyApiHandler", {
      handler: "handler",
      entry: "lambda/handler.ts",
    });

    const httpApi = new HttpApi(this, "MyHttpApi", {
      description: "My example HTTP API",
    });

    httpApi.addRoutes({
      path: "/hello",
      methods: [HttpMethod.GET],
      integration: new HttpLambdaIntegration("MyLambdaIntegration", myLambda),
    });

    const protectedApi = new WafHttpApi(this, "ProtectedMyApi", {
      httpApi: httpApi,
      // Optionally, provide custom WAF rules:
      // wafRules: [ ... ],
    });

    new cdk.CfnOutput(this, "ProtectedApiEndpoint", {
      value: protectedApi.distribution.distributionDomainName,
      description: "The CloudFront URL for the protected API endpoint",
    });

    new cdk.CfnOutput(this, "OriginVerificationSecret", {
      value: protectedApi.secretHeaderValue,
      description: "Secret value to verify CloudFront origin requests",
    });
  }
}

Custom Domain with Automatic Certificate

This example shows how to use a custom domain with automatic SSL certificate generation:

import { Stack, StackProps, CfnOutput } from "aws-cdk-lib";
import { HttpApi, HttpMethod } from "aws-cdk-lib/aws-apigatewayv2";
import { HttpLambdaIntegration } from "aws-cdk-lib/aws-apigatewayv2-integrations";
import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";
import { Runtime } from "aws-cdk-lib/aws-lambda";
import { WafHttpApi } from "waf-http-api";

class MyStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    // ... Lambda and HTTP API setup (same as above) ...

    const protectedApi = new WafHttpApi(this, "ProtectedMyApi", {
      httpApi: httpApi,
      domain: "api.example.com", // Custom domain
      // Certificate will be automatically generated with DNS validation
    });

    new CfnOutput(this, "CustomDomainEndpoint", {
      value: `https://${protectedApi.customDomain}`,
      description: "Custom domain API endpoint",
    });

    new CfnOutput(this, "CertificateArn", {
      value: protectedApi.certificate?.certificateArn || "No certificate",
      description: "Auto-generated SSL certificate ARN",
    });
  }
}

Custom Domain Configuration

Important: When using a custom domain, you must provide a hosted zone for DNS validation and automatic record creation.

import { Stack, StackProps, CfnOutput } from "aws-cdk-lib";
import { HttpApi, HttpMethod } from "aws-cdk-lib/aws-apigatewayv2";
import { HttpLambdaIntegration } from "aws-cdk-lib/aws-apigatewayv2-integrations";
import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";
import { Runtime } from "aws-cdk-lib/aws-lambda";
import { HostedZone } from "aws-cdk-lib/aws-route53";
import { WafHttpApi } from "waf-http-api";

class MyStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    // ... Lambda and HTTP API setup (same as above) ...

    // Reference an existing hosted zone (REQUIRED for custom domains)
    const hostedZone = HostedZone.fromLookup(this, "MyZone", {
      domainName: "example.com",
    });

    const protectedApi = new WafHttpApi(this, "ProtectedMyApi", {
      httpApi: httpApi,
      domain: "api.example.com",
      hostedZone: hostedZone, // REQUIRED when using custom domain
    });

    new CfnOutput(this, "CustomDomainEndpoint", {
      value: `https://${protectedApi.customDomain}`,
      description: "Custom domain API endpoint",
    });

    // Access the automatically created DNS records
    if (protectedApi.aRecord) {
      new CfnOutput(this, "ARecordName", {
        value: protectedApi.aRecord.domainName,
        description: "A record for the API domain",
      });
    }

    if (protectedApi.aaaaRecord) {
      new CfnOutput(this, "AAAARecordName", {
        value: protectedApi.aaaaRecord.domainName,
        description: "AAAA record for the API domain",
      });
    }
  }
}

Custom Domain with Provided Certificate

This example shows how to use a custom domain with your own SSL certificate (hosted zone still required):

import { Stack, StackProps, CfnOutput } from "aws-cdk-lib";
import { Certificate } from "aws-cdk-lib/aws-certificatemanager";
import { HttpApi, HttpMethod } from "aws-cdk-lib/aws-apigatewayv2";
import { HttpLambdaIntegration } from "aws-cdk-lib/aws-apigatewayv2-integrations";
import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";
import { Runtime } from "aws-cdk-lib/aws-lambda";
import { HostedZone } from "aws-cdk-lib/aws-route53";
import { WafHttpApi } from "waf-http-api";

class MyStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    // ... Lambda and HTTP API setup (same as above) ...

    // Reference an existing hosted zone (REQUIRED)
    const hostedZone = HostedZone.fromLookup(this, "MyZone", {
      domainName: "example.com",
    });

    // Reference an existing certificate (must be in us-east-1 region)
    const existingCertificate = Certificate.fromCertificateArn(
      this,
      "ExistingCert",
      "arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012",
    );

    const protectedApi = new WafHttpApi(this, "ProtectedMyApi", {
      httpApi: httpApi,
      domain: "api.example.com",
      hostedZone: hostedZone, // REQUIRED when using custom domain
      certificate: existingCertificate, // Use provided certificate
    });

    new CfnOutput(this, "CustomDomainEndpoint", {
      value: `https://${protectedApi.customDomain}`,
      description: "Custom domain API endpoint",
    });

    new CfnOutput(this, "CertificateArn", {
      value: protectedApi.certificate?.certificateArn || "No certificate",
      description: "Provided SSL certificate ARN",
    });
  }
}

Advanced Configuration with Custom WAF Rules

This example shows advanced usage with custom domain and custom WAF rules:

import { Stack, StackProps, CfnOutput } from "aws-cdk-lib";
import { HttpApi, HttpMethod } from "aws-cdk-lib/aws-apigatewayv2";
import { HttpLambdaIntegration } from "aws-cdk-lib/aws-apigatewayv2-integrations";
import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";
import { Runtime } from "aws-cdk-lib/aws-lambda";
import { HostedZone } from "aws-cdk-lib/aws-route53";
import { WafHttpApi } from "waf-http-api";

class MyStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    // ... Lambda and HTTP API setup (same as above) ...

    // Reference an existing hosted zone (REQUIRED for custom domains)
    const hostedZone = HostedZone.fromLookup(this, "MyZone", {
      domainName: "example.com",
    });

    const protectedApi = new WafHttpApi(this, "ProtectedMyApi", {
      httpApi: httpApi,
      domain: "secure-api.example.com",
      hostedZone: hostedZone, // REQUIRED when using custom domain
      wafRules: [
        {
          name: "RateLimitRule",
          priority: 10,
          statement: {
            rateBasedStatement: {
              limit: 2000,
              aggregateKeyType: "IP",
            },
          },
          action: { block: {} },
          visibilityConfig: {
            cloudWatchMetricsEnabled: true,
            metricName: "RateLimitRule",
            sampledRequestsEnabled: true,
          },
        },
        // Add more custom rules as needed
      ],
    });

    new CfnOutput(this, "SecureApiEndpoint", {
      value: `https://${protectedApi.customDomain}`,
      description: "Secure API endpoint with custom WAF rules",
    });
  }
}

Important Notes

Certificate Requirements

  • Region Requirement: SSL certificates for CloudFront must be in the us-east-1 region
  • DNS Validation: Auto-generated certificates use DNS validation through the provided hosted zone
  • Domain Ownership: You must own and control the domain and have access to the hosted zone

Domain Configuration

  • Supported Formats: Apex domains (example.com), subdomains (api.example.com), and wildcards (*.example.com)
  • Hosted Zone Required: All custom domains require a corresponding hosted zone for DNS validation and record creation
  • Automatic DNS Setup: DNS records are automatically created in the provided hosted zone
  • Validation: Domain format and hosted zone compatibility are validated at synthesis time

Hosted Zone Requirements

  • Required for Custom Domains: A hosted zone is required when using custom domains for DNS validation and record creation
  • Automatic DNS Records: Route 53 A and AAAA records are automatically created for the custom domain
  • Domain Compatibility: The domain must match or be a subdomain of the hosted zone's domain
  • Record Types: Both IPv4 (A) and IPv6 (AAAA) records are created pointing to the CloudFront distribution

API

See API.md for full API documentation.

Development

This project uses projen for project management. To synthesize project files after making changes to .projenrc.ts, run:

npx projen

License

MIT © Merapar Technologies Group B.V.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

waf_http_api-1.2.0.tar.gz (129.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

waf_http_api-1.2.0-py3-none-any.whl (127.1 kB view details)

Uploaded Python 3

File details

Details for the file waf_http_api-1.2.0.tar.gz.

File metadata

  • Download URL: waf_http_api-1.2.0.tar.gz
  • Upload date:
  • Size: 129.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for waf_http_api-1.2.0.tar.gz
Algorithm Hash digest
SHA256 2868ee2c48f04007f23691a4e24851d2917491329cfb04932193355b5f0e5b27
MD5 38012230e0b2ada3f478c3a620c9517e
BLAKE2b-256 7fa6e133b04774bcfd45bd55c280b3d0d8a2bfad3001acac53c832746414e388

See more details on using hashes here.

File details

Details for the file waf_http_api-1.2.0-py3-none-any.whl.

File metadata

  • Download URL: waf_http_api-1.2.0-py3-none-any.whl
  • Upload date:
  • Size: 127.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for waf_http_api-1.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7b92c5078bb089d7f753042fec68681bbe7535047dba3b99f3f873017b082910
MD5 5394ee55367b91157fd22cbcf8d8fb8f
BLAKE2b-256 079e0fbe8eb279592ad8dd01be89e76670d9e95a4738527d8cc07b109ca6661f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page