From 0d1bdf4f3e8d4bcdd851c152a335bc7824060e23 Mon Sep 17 00:00:00 2001 From: Nithin Chandran Rajashankar Date: Thu, 18 Jun 2026 19:06:12 +0000 Subject: [PATCH] feat(waf): Add AWS WAF AI traffic monetization with Amazon CloudFront (CDK) --- waf-cloudfront-ai-monetization-cdk/.gitignore | 5 + waf-cloudfront-ai-monetization-cdk/README.md | 120 +++++++++++++++++ waf-cloudfront-ai-monetization-cdk/bin/app.ts | 12 ++ waf-cloudfront-ai-monetization-cdk/cdk.json | 3 + .../example-pattern.json | 98 ++++++++++++++ .../waf-cloudfront-ai-monetization-stack.ts | 122 ++++++++++++++++++ .../package.json | 22 ++++ .../tsconfig.json | 17 +++ 8 files changed, 399 insertions(+) create mode 100644 waf-cloudfront-ai-monetization-cdk/.gitignore create mode 100644 waf-cloudfront-ai-monetization-cdk/README.md create mode 100644 waf-cloudfront-ai-monetization-cdk/bin/app.ts create mode 100644 waf-cloudfront-ai-monetization-cdk/cdk.json create mode 100644 waf-cloudfront-ai-monetization-cdk/example-pattern.json create mode 100644 waf-cloudfront-ai-monetization-cdk/lib/waf-cloudfront-ai-monetization-stack.ts create mode 100644 waf-cloudfront-ai-monetization-cdk/package.json create mode 100644 waf-cloudfront-ai-monetization-cdk/tsconfig.json diff --git a/waf-cloudfront-ai-monetization-cdk/.gitignore b/waf-cloudfront-ai-monetization-cdk/.gitignore new file mode 100644 index 0000000000..46052f7ff4 --- /dev/null +++ b/waf-cloudfront-ai-monetization-cdk/.gitignore @@ -0,0 +1,5 @@ +node_modules +build +cdk.out +cdk.context.json +package-lock.json diff --git a/waf-cloudfront-ai-monetization-cdk/README.md b/waf-cloudfront-ai-monetization-cdk/README.md new file mode 100644 index 0000000000..c595c63d58 --- /dev/null +++ b/waf-cloudfront-ai-monetization-cdk/README.md @@ -0,0 +1,120 @@ +# AWS WAF AI Traffic Monetization with Amazon CloudFront (CDK) + +This pattern deploys an Amazon CloudFront distribution protected by AWS WAF with AI traffic monetization enabled. AI bots that access your content are automatically charged via the x402 payment protocol using USDC stablecoins. + +Learn more about this pattern at Serverless Land Patterns: https://serverlessland.com/patterns/waf-cloudfront-ai-monetization-cdk + +Important: this application uses various AWS services and there are costs associated with these services after the Free Tier usage - please see the [AWS Pricing page](https://aws.amazon.com/pricing/) for details. You are responsible for any AWS costs incurred. No warranty is implied in this example. + +## Requirements + +* [Create an AWS account](https://portal.aws.amazon.com/gp/aws/developer/registration/index.html) if you do not already have one and log in. The IAM user that you use must have sufficient permissions to make necessary AWS service calls and manage AWS resources. +* [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) installed and configured +* [Git Installed](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) +* [Node.js 20+](https://nodejs.org/en/download/) installed +* [AWS CDK v2](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html) installed and bootstrapped + +## Deployment Instructions + +1. Create a new directory, navigate to that directory in a terminal and clone the GitHub repository: + ``` + git clone https://github.com/aws-samples/serverless-patterns + ``` +2. Change directory to the pattern directory: + ``` + cd serverless-patterns/waf-cloudfront-ai-monetization-cdk + ``` +3. Install dependencies: + ``` + npm install + ``` +4. Deploy the stack (must deploy to us-east-1 for Amazon CloudFront): + ``` + cdk deploy + ``` + +## How it works + +This pattern creates: + +1. **Amazon S3 bucket** — stores your content (HTML, APIs, data) that AI bots want to access. +2. **Amazon CloudFront distribution** — serves content globally with HTTPS. +3. **AWS WAF WebACL** (CLOUDFRONT scope) with: + - **Bot Control managed rule group** — uses machine learning to classify bots into categories (AI, scraper, crawler, etc.) + - **MonetizeAction rule** — matches bots labeled `awswaf:managed:aws:bot-control:bot:category:ai` and returns HTTP 402 with an x402 payment manifest + - **MonetizationConfig** — configures the x402 payment network (Base Sepolia testnet by default), wallet address, and USDC pricing + +### Flow + +``` +AI Bot Request + │ + ▼ +CloudFront Distribution + │ + ▼ +AWS WAF Bot Control (classifies bot category) + │ + ├── Human browser → Allow (200 OK) + │ + └── AI Bot (GPTBot, ClaudeBot, etc.) + │ + ▼ + MonetizeAction → HTTP 402 Payment Required + │ (x402 price manifest) + │ + ├── Bot pays USDC → Request replayed → 200 OK + │ + └── Bot doesn't pay → Blocked +``` + +### Test Mode + +The pattern deploys in **TEST mode** using Base Sepolia testnet. No real money is involved. To switch to production: + +1. Replace the wallet address with your production USDC wallet (Base or Solana) +2. Change `CurrencyMode` from `TEST` to `LIVE` +3. Change `Chain` from `BASE_SEPOLIA` to `BASE` (or `SOLANA`) + +## Testing + +1. Upload sample content: + ```bash + echo '

Premium Content

' > index.html + aws s3 cp index.html s3://$(aws cloudformation describe-stacks \ + --stack-name WafCloudfrontAiMonetizationStack \ + --query 'Stacks[0].Outputs[?OutputKey==`ContentBucketName`].OutputValue' \ + --output text)/index.html --content-type text/html + ``` + +2. Test with a normal browser (should return 200 OK): + ```bash + curl -s -o /dev/null -w "%{http_code}" \ + https://$(aws cloudformation describe-stacks \ + --stack-name WafCloudfrontAiMonetizationStack \ + --query 'Stacks[0].Outputs[?OutputKey==`DistributionDomainName`].OutputValue' \ + --output text)/index.html + ``` + +3. Test with an AI bot User-Agent (should return 402 Payment Required): + ```bash + curl -s -D - -H 'User-Agent: GPTBot/1.0' \ + https://$(aws cloudformation describe-stacks \ + --stack-name WafCloudfrontAiMonetizationStack \ + --query 'Stacks[0].Outputs[?OutputKey==`DistributionDomainName`].OutputValue' \ + --output text)/index.html + ``` + The response headers will include the x402 payment manifest with pricing details. + +## Cleanup + +```bash +cdk destroy +``` + +**Warning**: The Amazon S3 bucket has a DESTROY removal policy. All objects in the bucket will be permanently deleted when the stack is destroyed. + +---- +Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +SPDX-License-Identifier: MIT-0 diff --git a/waf-cloudfront-ai-monetization-cdk/bin/app.ts b/waf-cloudfront-ai-monetization-cdk/bin/app.ts new file mode 100644 index 0000000000..a67fc086d6 --- /dev/null +++ b/waf-cloudfront-ai-monetization-cdk/bin/app.ts @@ -0,0 +1,12 @@ +#!/usr/bin/env node +import 'source-map-support/register'; +import * as cdk from 'aws-cdk-lib'; +import { WafCloudfrontAiMonetizationStack } from '../lib/waf-cloudfront-ai-monetization-stack'; + +const app = new cdk.App(); +new WafCloudfrontAiMonetizationStack(app, 'WafCloudfrontAiMonetizationStack', { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT, + region: 'us-east-1', // Required: WAF for CloudFront must be in us-east-1 + }, +}); diff --git a/waf-cloudfront-ai-monetization-cdk/cdk.json b/waf-cloudfront-ai-monetization-cdk/cdk.json new file mode 100644 index 0000000000..a6700a2ff4 --- /dev/null +++ b/waf-cloudfront-ai-monetization-cdk/cdk.json @@ -0,0 +1,3 @@ +{ + "app": "npx ts-node --prefer-ts-exts bin/app.ts" +} diff --git a/waf-cloudfront-ai-monetization-cdk/example-pattern.json b/waf-cloudfront-ai-monetization-cdk/example-pattern.json new file mode 100644 index 0000000000..5993055da5 --- /dev/null +++ b/waf-cloudfront-ai-monetization-cdk/example-pattern.json @@ -0,0 +1,98 @@ +{ + "title": "AWS WAF AI Traffic Monetization with Amazon CloudFront (CDK)", + "description": "Deploy AWS WAF AI traffic monetization with Amazon CloudFront to automatically charge AI bots for content access using the x402 payment protocol.", + "language": "TypeScript", + "level": "200", + "framework": "AWS CDK", + "introBox": { + "headline": "How it works", + "text": [ + "This pattern deploys an Amazon CloudFront distribution protected by an AWS WAF WebACL configured with Bot Control and AI traffic monetization.", + "When AI bots (crawlers, scrapers, LLM training agents) request content, AWS WAF classifies them using Bot Control's machine learning and returns an HTTP 402 Payment Required response with a price manifest.", + "Bots that complete payment via the x402 protocol (USDC on Base or Solana) are granted access. Bots that don't pay are blocked.", + "The pattern deploys in TEST mode using Base Sepolia testnet — no real money is involved until you switch to production mode." + ] + }, + "gitHub": { + "template": { + "repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/waf-cloudfront-ai-monetization-cdk", + "templateURL": "serverless-patterns/waf-cloudfront-ai-monetization-cdk", + "projectFolder": "waf-cloudfront-ai-monetization-cdk", + "templateFile": "lib/waf-cloudfront-ai-monetization-stack.ts" + } + }, + "resources": { + "bullets": [ + { + "text": "AWS WAF Bot Control - AI Traffic Monetization", + "link": "https://aws.amazon.com/waf/features/bot-control/" + }, + { + "text": "x402 Protocol Specification", + "link": "https://www.x402.org/" + }, + { + "text": "AWS WAF MonetizeAction CloudFormation Reference", + "link": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-monetizeaction.html" + } + ] + }, + "deploy": { + "text": [ + "cdk bootstrap", + "npm install", + "cdk deploy" + ] + }, + "testing": { + "text": [ + "Upload sample content to the Amazon S3 bucket:", + "aws s3 cp index.html s3://$(aws cloudformation describe-stacks --stack-name WafCloudfrontAiMonetizationStack --query 'Stacks[0].Outputs[?OutputKey==`ContentBucketName`].OutputValue' --output text)/index.html", + "Test with a normal browser request (should succeed):", + "curl -s https://$(aws cloudformation describe-stacks --stack-name WafCloudfrontAiMonetizationStack --query 'Stacks[0].Outputs[?OutputKey==`DistributionDomainName`].OutputValue' --output text)/index.html", + "Test with an AI bot User-Agent (should return HTTP 402 with x402 payment manifest):", + "curl -s -D - -H 'User-Agent: GPTBot/1.0' https://$(aws cloudformation describe-stacks --stack-name WafCloudfrontAiMonetizationStack --query 'Stacks[0].Outputs[?OutputKey==`DistributionDomainName`].OutputValue' --output text)/index.html" + ] + }, + "cleanup": { + "text": [ + "cdk destroy", + "Note: The Amazon S3 bucket has a DESTROY removal policy and will be deleted automatically with all objects." + ] + }, + "authors": [ + { + "name": "Nithin Chandran R", + "bio": "Technical Account Manager at AWS", + "linkedin": "nithin-chandran-r" + } + ], + "patternArch": { + "icon1": { + "x": 20, + "y": 50, + "service": "waf", + "label": "AWS WAF" + }, + "icon2": { + "x": 50, + "y": 50, + "service": "cloudfront", + "label": "Amazon CloudFront" + }, + "icon3": { + "x": 80, + "y": 50, + "service": "s3", + "label": "Amazon S3" + }, + "line1": { + "from": "icon1", + "to": "icon2" + }, + "line2": { + "from": "icon2", + "to": "icon3" + } + } +} diff --git a/waf-cloudfront-ai-monetization-cdk/lib/waf-cloudfront-ai-monetization-stack.ts b/waf-cloudfront-ai-monetization-cdk/lib/waf-cloudfront-ai-monetization-stack.ts new file mode 100644 index 0000000000..adb93910dc --- /dev/null +++ b/waf-cloudfront-ai-monetization-cdk/lib/waf-cloudfront-ai-monetization-stack.ts @@ -0,0 +1,122 @@ +import * as cdk from 'aws-cdk-lib'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as cloudfront from 'aws-cdk-lib/aws-cloudfront'; +import * as origins from 'aws-cdk-lib/aws-cloudfront-origins'; +import * as wafv2 from 'aws-cdk-lib/aws-wafv2'; +import { Construct } from 'constructs'; + +export class WafCloudfrontAiMonetizationStack extends cdk.Stack { + constructor(scope: Construct, id: string, props?: cdk.StackProps) { + super(scope, id, props); + + // Amazon S3 bucket for sample content + const contentBucket = new s3.Bucket(this, 'ContentBucket', { + removalPolicy: cdk.RemovalPolicy.DESTROY, + autoDeleteObjects: true, + }); + + // WAF WebACL with Bot Control and AI Traffic Monetization + const webAcl = new wafv2.CfnWebACL(this, 'AiMonetizationWebAcl', { + defaultAction: { allow: {} }, + scope: 'CLOUDFRONT', + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'AiMonetizationWebAcl', + sampledRequestsEnabled: true, + }, + rules: [ + { + name: 'AWSManagedRulesBotControlRuleSet', + priority: 0, + overrideAction: { count: {} }, + statement: { + managedRuleGroupStatement: { + vendorName: 'AWS', + name: 'AWSManagedRulesBotControlRuleSet', + managedRuleGroupConfigs: [ + { + awsManagedRulesBotControlRuleSet: { + inspectionLevel: 'TARGETED', + enableMachineLearning: true, + }, + }, + ], + }, + }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'BotControlRuleSet', + sampledRequestsEnabled: true, + }, + }, + { + name: 'MonetizeAiBots', + priority: 1, + action: { count: {} }, // Placeholder — overridden below + statement: { + labelMatchStatement: { + scope: 'LABEL', + key: 'awswaf:managed:aws:bot-control:bot:category:ai', + }, + }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: 'MonetizeAiBots', + sampledRequestsEnabled: true, + }, + }, + ], + }); + + // Override the MonetizeAiBots rule action with Monetize (not yet in CDK types) + webAcl.addPropertyDeletionOverride('Rules.1.Action.Count'); + webAcl.addPropertyOverride('Rules.1.Action.Monetize', { + PriceMultiplier: 10, + }); + + // Add MonetizationConfig to the WebACL (not yet in CDK types) + // Using TEST mode with Base Sepolia testnet — no real money involved + webAcl.addPropertyOverride('MonetizationConfig', { + CurrencyMode: 'TEST', + CryptoConfig: { + PaymentNetworks: [ + { + Chain: 'BASE_SEPOLIA', + WalletAddress: '0x0000000000000000000000000000000000000000', // Replace with your testnet wallet + Prices: [ + { + Amount: '0.001', + Currency: 'USDC', + }, + ], + }, + ], + }, + }); + + // CloudFront distribution with WAF protection + const distribution = new cloudfront.Distribution(this, 'Distribution', { + defaultBehavior: { + origin: origins.S3BucketOrigin.withOriginAccessControl(contentBucket), + viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, + }, + webAclId: webAcl.attrArn, + }); + + // Outputs + new cdk.CfnOutput(this, 'DistributionDomainName', { + value: distribution.distributionDomainName, + description: 'Amazon CloudFront distribution domain name', + }); + + new cdk.CfnOutput(this, 'ContentBucketName', { + value: contentBucket.bucketName, + description: 'Amazon S3 bucket for sample content', + }); + + new cdk.CfnOutput(this, 'WebAclArn', { + value: webAcl.attrArn, + description: 'AWS WAF WebACL ARN', + }); + } +} diff --git a/waf-cloudfront-ai-monetization-cdk/package.json b/waf-cloudfront-ai-monetization-cdk/package.json new file mode 100644 index 0000000000..3b748c76b1 --- /dev/null +++ b/waf-cloudfront-ai-monetization-cdk/package.json @@ -0,0 +1,22 @@ +{ + "name": "waf-cloudfront-ai-monetization-cdk", + "version": "1.0.0", + "bin": { + "app": "bin/app.ts" + }, + "scripts": { + "build": "tsc", + "cdk": "cdk" + }, + "dependencies": { + "aws-cdk-lib": "^2.260.0", + "constructs": "^10.0.0", + "source-map-support": "^0.5.21" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "typescript": "~5.4.0", + "aws-cdk": "^2.260.0", + "ts-node": "^10.9.0" + } +} diff --git a/waf-cloudfront-ai-monetization-cdk/tsconfig.json b/waf-cloudfront-ai-monetization-cdk/tsconfig.json new file mode 100644 index 0000000000..ae328a5827 --- /dev/null +++ b/waf-cloudfront-ai-monetization-cdk/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["es2020"], + "declaration": true, + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "noImplicitThis": true, + "alwaysStrict": true, + "outDir": "build", + "rootDir": ".", + "typeRoots": ["./node_modules/@types"] + }, + "exclude": ["node_modules", "build"] +}