Zum Hauptinhalt springen
tsecurity.de LIVE
Echtzeit-Radar & Feeds
Alle RSS Feeds
👥 Community & Social
YouTube Security VideosAndroid Police: Samsung is smashing records! #shorts #tech #phones(21.09.2026 um 13:55 Uhr)
YouTube Security Videosheise & c't: Bundesnetzagentur wollte diesen Futterautomaten verbieten(21.09.2026 um 13:53 Uhr)
YouTube Security VideosNeil Patel: Your Google Traffic Isn't An Asset It's A Loan #shorts(21.09.2026 um 14:05 Uhr)
Windows Tipps & SecurityF-14 A Tomcat Top Gun endlich als Revell Klemmbausteinmodell erhältlich(21.09.2026 um 14:27 Uhr)
Sichere ProgrammierungShow the Hand-Back Sample Before Approving an Agent Score(21.09.2026 um 14:15 Uhr)
Sichere ProgrammierungHybrid retrieval in one Postgres query: RRF over tsvector + pgvector(21.09.2026 um 14:15 Uhr)
YouTube Security VideosAndroid Police: Samsung is smashing records! #shorts #tech #phones(21.09.2026 um 13:55 Uhr)
YouTube Security Videosheise & c't: Bundesnetzagentur wollte diesen Futterautomaten verbieten(21.09.2026 um 13:53 Uhr)
YouTube Security VideosNeil Patel: Your Google Traffic Isn't An Asset It's A Loan #shorts(21.09.2026 um 14:05 Uhr)
Windows Tipps & SecurityF-14 A Tomcat Top Gun endlich als Revell Klemmbausteinmodell erhältlich(21.09.2026 um 14:27 Uhr)
Sichere ProgrammierungShow the Hand-Back Sample Before Approving an Agent Score(21.09.2026 um 14:15 Uhr)
Sichere ProgrammierungHybrid retrieval in one Postgres query: RRF over tsvector + pgvector(21.09.2026 um 14:15 Uhr)
Intelligence View
⚡ tsecurity.de Intelligence

Building an A/B Testing System with CloudFront Functions using AWS CDK

Prerequisites Why This is Needed Amazon CloudFront + Amazon S3 is an essential configuration for delivering frontend content on AWS. Additionally, A/B testing is an indispensable method for improving web services. However,…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!




Prerequisites






Why This is Needed



Amazon CloudFront + Amazon S3 is an essential configuration for delivering frontend content on AWS.

Additionally, A/B testing is an indispensable method for improving web services.



However, implementing A/B testing with traditional configurations requires implementation in frontend code or APIs.

This adds complexity to application logic since it requires modifications to the application layer.



In April 2025, there was an update that enabled origin switching with CloudFront Functions.










This time, we'll explore how to easily implement A/B testing by switching between S3 buckets using the selectRequestOriginById() method in CloudFront Functions.



Benefits of Using CloudFront Functions





  • High-speed processing at the edge: Instant decisions at locations closest to users


  • Simple implementation: Concise JavaScript code that's easy to deploy


  • Infrastructure separation: Separates application code from A/B testing logic, improving maintainability



This approach enables efficient A/B testing without sacrificing performance.






Required Knowledge




  • Basic understanding of AWS CDK (Cloud Development Kit)

  • Basic knowledge of TypeScript/JavaScript

  • Basic concepts of AWS CloudFront and S3

  • Understanding of A/B testing concepts






Required Environment




  • Node.js (v18 or higher recommended)

  • AWS CLI configured

  • AWS CDK CLI (npm install -g aws-cdk)

  • TypeScript environment






AWS Services Used





  • Amazon S3: Static website hosting (two buckets)


  • Amazon CloudFront: CDN distribution and A/B testing logic


  • CloudFront Function: Request routing control


  • Origin Access Control (OAC): Secure access control to S3 buckets






Setup






1. Project Initialization






# Create CDK project
mkdir cloudfront-ab-testing
cd cloudfront-ab-testing
cdk init app --language typescript







2. Project Structure Setup





cloudfront-ab-testing/
├── lib/
│ ├── cloudfront-ab-testing.ts # Main stack
│ └── ab-test-function.js # CloudFront Function
├── assets/
│ ├── site-a/
│ │ └── index.html # Variant A
│ └── site-b/
│ └── index.html # Variant B
└── package.json







Implementation Steps





1. CloudFront Function Implementation



Create a CloudFront Function that handles A/B testing logic:



// lib/ab-test-function.js
import cf from 'cloudfront';

function handler(event) {
var request = event.request;
var headers = request.headers;

// Check X-AB-Test header
if (headers['x-ab-test'] && headers['x-ab-test'].value === 'variant-b') {
// Select Origin B
cf.selectRequestOriginById('BUCKET_B_ORIGIN_ID');
} else {
// Select Origin A by default (variant-a or no header)
cf.selectRequestOriginById('BUCKET_A_ORIGIN_ID');
}

return request;
}







2. S3 Bucket Creation



Create two S3 buckets to host different content:



// S3 Bucket A (for variant-a)
const bucketA = new s3.Bucket(this, 'BucketA', {
removalPolicy: cdk.RemovalPolicy.DESTROY,
autoDeleteObjects: true,
});

// S3 Bucket B (for variant-b)
const bucketB = new s3.Bucket(this, 'BucketB', {
removalPolicy: cdk.RemovalPolicy.DESTROY,
autoDeleteObjects: true,
});







3. Origin Access Control (OAC) Configuration



Configure OAC to ensure secure access to S3 buckets:



const originAccessControl = new cloudfront.CfnOriginAccessControl(this, 'OriginAccessControl', {
originAccessControlConfig: {
name: 'ABTestOAC',
originAccessControlOriginType: 's3',
signingBehavior: 'always',
signingProtocol: 'sigv4',
description: 'OAC for A/B testing CloudFront distribution',
},
});







4. Custom Cache Policy Creation



Create a custom policy that includes A/B test headers in the cache key:



const customCachePolicy = new cloudfront.CfnCachePolicy(this, 'ABTestCachePolicy', {
cachePolicyConfig: {
name: 'ABTestCachePolicy',
comment: 'Cache policy that includes x-ab-test header as cache key',
defaultTtl: 86400, // 1 day
maxTtl: 31536000, // 1 year
minTtl: 0,
parametersInCacheKeyAndForwardedToOrigin: {
enableAcceptEncodingGzip: true,
enableAcceptEncodingBrotli: true,
headersConfig: {
headerBehavior: 'whitelist',
headers: ['x-ab-test'],
},
queryStringsConfig: {
queryStringBehavior: 'none',
},
cookiesConfig: {
cookieBehavior: 'none',
},
},
},
});







5. CloudFront Distribution Configuration



Configure distribution with multiple origins and CloudFront Function:



const distribution = new cloudfront.CfnDistribution(this, 'CloudFrontDistribution', {
distributionConfig: {
enabled: true,
priceClass: 'PriceClass_100',
origins: [
{
id: bucketAOriginId,
domainName: bucketA.bucketDomainName,
s3OriginConfig: {
originAccessIdentity: '',
},
originAccessControlId: originAccessControl.attrId,
},
{
id: bucketBOriginId,
domainName: bucketB.bucketDomainName,
s3OriginConfig: {
originAccessIdentity: '',
},
originAccessControlId: originAccessControl.attrId,
},
],
defaultCacheBehavior: {
targetOriginId: bucketAOriginId,
viewerProtocolPolicy: 'redirect-to-https',
cachePolicyId: customCachePolicy.ref,
compress: true,
functionAssociations: [
{
eventType: 'viewer-request',
functionArn: abTestFunction.functionArn,
},
],
},
},
});







6. S3 Bucket Policy Configuration



Configure access permissions from CloudFront using OAC:



const bucketAPolicyStatement = new iam.PolicyStatement({
actions: ['s3:GetObject'],
resources: [bucketA.arnForObjects('*')],
principals: [new iam.ServicePrincipal('cloudfront.amazonaws.com')],
conditions: {
StringEquals: {
'AWS:SourceArn': `arn:aws:cloudfront::${this.account}:distribution/${distribution.ref}`,
},
},
});

bucketA.addToResourcePolicy(bucketAPolicyStatement);







7. Content Deployment



Deploy static files to S3 buckets:



// Upload Site A files to BucketA
new s3deploy.BucketDeployment(this, 'DeploySiteA', {
sources: [s3deploy.Source.asset('./assets/site-a')],
destinationBucket: bucketA,
});

// Upload Site B files to BucketB
new s3deploy.BucketDeployment(this, 'DeploySiteB', {
sources: [s3deploy.Source.asset('./assets/site-b')],
destinationBucket: bucketB,
});







8. Complete Stack Implementation



The complete main stack implementation, integrating all the previous steps, is as
follows:




import * as cdk from 'aws-cdk-lib/core';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as s3deploy from 'aws-cdk-lib/aws-s3-deployment';
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront';
import * as iam from 'aws-cdk-lib/aws-iam';
import { Construct } from 'constructs';
import * as fs from 'fs';
import * as path from 'path';

export class CloudfrontAbTestingStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);

// S3 Bucket A (for variant-a)
const bucketA = new s3.Bucket(this, 'BucketA', {
removalPolicy: cdk.RemovalPolicy.DESTROY,
autoDeleteObjects: true,
});

// S3 Bucket B (for variant-b)
const bucketB = new s3.Bucket(this, 'BucketB', {
removalPolicy: cdk.RemovalPolicy.DESTROY,
autoDeleteObjects: true,
});

// Origin Access Control (OAC) - New recommended approach
const originAccessControl = new cloudfront.CfnOriginAccessControl(this, 'OriginAccessControl', {
originAccessControlConfig: {
name: 'ABTestOAC',
originAccessControlOriginType: 's3',
signingBehavior: 'always',
signingProtocol: 'sigv4',
description: 'OAC for A/B testing CloudFront distribution',
},
});

// Define Origin IDs as constants
const bucketAOriginId = 'BucketAOrigin';
const bucketBOriginId = 'BucketBOrigin';

// CloudFront Function for A/B testing
// Load Function code from external file
const functionCodePath = path.join(__dirname, 'ab-test-function.js');
let functionCode = fs.readFileSync(functionCodePath, 'utf8');

// Replace placeholders with actual values
functionCode = functionCode
.replaceAll('BUCKET_A_ORIGIN_ID', bucketAOriginId)
.replaceAll('BUCKET_B_ORIGIN_ID', bucketBOriginId);

const abTestFunction = new cloudfront.Function(this, 'ABTestFunction', {
code: cloudfront.FunctionCode.fromInline(functionCode),
comment: 'A/B testing function to route requests based on X-AB-Test header',
runtime: cloudfront.FunctionRuntime.JS_2_0, // Specify JavaScript Runtime 2.0
});

// Custom cache policy (include x-ab-test header in cache key)
const customCachePolicy = new cloudfront.CfnCachePolicy(this, 'ABTestCachePolicy', {
cachePolicyConfig: {
name: 'ABTestCachePolicy',
comment: 'Cache policy that includes x-ab-test header as cache key',
defaultTtl: 86400, // 1 day
maxTtl: 31536000, // 1 year
minTtl: 0,
parametersInCacheKeyAndForwardedToOrigin: {
enableAcceptEncodingGzip: true,
enableAcceptEncodingBrotli: true,
headersConfig: {
headerBehavior: 'whitelist',
headers: ['x-ab-test'],
},
queryStringsConfig: {
queryStringBehavior: 'none',
},
cookiesConfig: {
cookieBehavior: 'none',
},
},
},
});

// CloudFront Distribution (using low-level API for precise control)
const distribution = new cloudfront.CfnDistribution(this, 'CloudFrontDistribution', {
distributionConfig: {
enabled: true,
priceClass: 'PriceClass_100',
origins: [
{
id: bucketAOriginId,
domainName: bucketA.bucketDomainName,
s3OriginConfig: {
originAccessIdentity: '', // Empty string when using OAC
},
originAccessControlId: originAccessControl.attrId,
},
{
id: bucketBOriginId,
domainName: bucketB.bucketDomainName,
s3OriginConfig: {
originAccessIdentity: '', // Empty string when using OAC
},
originAccessControlId: originAccessControl.attrId,
},
],
defaultCacheBehavior: {
targetOriginId: bucketAOriginId,
viewerProtocolPolicy: 'redirect-to-https',
cachePolicyId: customCachePolicy.ref, // Use custom cache policy
compress: true,
functionAssociations: [
{
eventType: 'viewer-request',
functionArn: abTestFunction.functionArn,
},
],
},
},
});

// Bucket A policy (for OAC) - Set after Distribution creation
const bucketAPolicyStatement = new iam.PolicyStatement({
actions: ['s3:GetObject'],
resources: [bucketA.arnForObjects('*')],
principals: [new iam.ServicePrincipal('cloudfront.amazonaws.com')],
conditions: {
StringEquals: {
'AWS:SourceArn': `arn:aws:cloudfront::${this.account}:distribution/${distribution.ref}`,
},
},
});

bucketA.addToResourcePolicy(bucketAPolicyStatement);

// Bucket B policy (for OAC) - Set after Distribution creation
const bucketBPolicyStatement = new iam.PolicyStatement({
actions: ['s3:GetObject'],
resources: [bucketB.arnForObjects('*')],
principals: [new iam.ServicePrincipal('cloudfront.amazonaws.com')],
conditions: {
StringEquals: {
'AWS:SourceArn': `arn:aws:cloudfront::${this.account}:distribution/${distribution.ref}`,
},
},
});

bucketB.addToResourcePolicy(bucketBPolicyStatement);

// Deploy HTML files to S3 buckets
// Upload Site A files to BucketA
new s3deploy.BucketDeployment(this, 'DeploySiteA', {
sources: [s3deploy.Source.asset('./assets/site-a')],
destinationBucket: bucketA,
});

// Upload Site B files to BucketB
new s3deploy.BucketDeployment(this, 'DeploySiteB', {
sources: [s3deploy.Source.asset('./assets/site-b')],
destinationBucket: bucketB,
});

// Stack outputs
new cdk.CfnOutput(this, 'CloudFrontDomainName', {
value: distribution.attrDomainName,
description: 'CloudFront Distribution domain name',
});

new cdk.CfnOutput(this, 'BucketAName', {
value: bucketA.bucketName,
description: 'S3 Bucket A name',
});

new cdk.CfnOutput(this, 'BucketBName', {
value: bucketB.bucketName,
description: 'S3 Bucket B name',
});

new cdk.CfnOutput(this, 'ABTestHeaderExample', {
value: 'X-AB-Test: variant-a or X-AB-Test: variant-b',
description: 'A/B test header usage examples',
});
}
}









Full sample project is below:





GitHub logo

tacck
/
cloudfront-ab-testing



Check A/B testing on CloudFront







Welcome to your CDK TypeScript project





This is a blank project for CDK development with TypeScript.



The cdk.json file tells the CDK Toolkit how to execute your app.




Useful commands







  • npm run build compile typescript to js


  • npm run watch watch for changes and compile


  • npm run test perform the jest unit tests


  • npx cdk deploy deploy this stack to your default AWS account/region


  • npx cdk diff compare deployed stack with current state


  • npx cdk synth emits the synthesized CloudFormation template




Permison Boundly






Bootstraping





cdk bootstrap --custom-permissions-boundary builder-permissions-boundary 

https://dev.classmethod.jp/articles/cdk-minimum-deploy-policy/



Check





curl -i  https://[YOUR_CLOUDFRONT_SITE]/index.html
curl -i -H 'x-ab-test: variant-a' https://[YOUR_CLOUDFRONT_SITE]/index.html

curl -i -H 'x-ab-test: variant-b' https://[YOUR_CLOUDFRONT_SITE]/index.html












9. Deployment and Testing






# Deploy CDK stack
cdk deploy

# Test A/B functionality
# Default (Variant A)
curl -i https://[YOUR_CLOUDFRONT_DOMAIN]/index.html

# Variant A (explicit specification)
curl -i -H 'X-AB-Test: variant-a' https://[YOUR_CLOUDFRONT_DOMAIN]/index.html

# Variant B
curl -i -H 'X-AB-Test: variant-b' https://[YOUR_CLOUDFRONT_DOMAIN]/index.html









Summary



This A/B testing system combines the following technical elements:






Key Features





  • CloudFront Function: Dynamic origin selection based on request headers


  • Origin Access Control (OAC): Latest security best practices


  • Custom Cache Policy: Cache strategy considering A/B test headers


  • Infrastructure as Code: Reproducible infrastructure construction with CDK






Benefits





  1. Low Latency: CloudFront Functions execute at the edge for high speed


  2. Cost Efficiency: 1 million executions free, then $0.10 USD per million executions


  3. Scalable: Leverages CloudFront's global network


  4. Secure: Proper access control with OAC






Application Possibilities




  • Regional content distribution

  • Device-specific optimization

  • Gradual feature releases (canary deployment)

  • Query parameter-based A/B testing

  • Personalization



This system can serve as a foundation for implementing more complex A/B testing and traffic distribution logic.

Using CDK makes infrastructure changes easy to manage, enabling continuous improvement and testing.

Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Building an A/B Testing System with CloudFront Functions using AWS CDK

Thematisch verwandte Begriffe: Building, Testing, System, with · 6 Treffer

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-94097 | A vulnerability was determined in Netcore NBR200V2 1.3.241127.071246. Th…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel Rechts: nächster Artikel unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

Zurück: vorheriger Vor: nächster
↗ Original-Quelle
Social Reaktionen Deine Reaktion zählt
Einstufung & Relevanz-Poll 0 Stimmen
In sozialen Netzwerken teilen 1-Klick