Loading...
Loading...
S3 + CloudFront + Lambda@Edge for low-cost global hosting with edge authentication. Apply when setting up frontend hosting infrastructure.
npx skill4agent add loxosceles/ai-dev static-frontend-hostingUser Request
↓
CloudFront (CDN)
↓
Lambda@Edge (us-east-1) ← Validates token, sets cookies
↓
S3 Bucket (Static Files)const websiteBucket = new s3.Bucket(this, 'WebsiteBucket', {
bucketName: `${PROJECT_ID}-web-${environment}`,
blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, // Not public!
removalPolicy: cdk.RemovalPolicy.DESTROY
});const distribution = new cloudfront.Distribution(this, 'Distribution', {
defaultBehavior: {
origin: new origins.S3Origin(websiteBucket),
viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
edgeLambdas: [{
functionVersion: authFunction.currentVersion,
eventType: cloudfront.LambdaEdgeEventType.VIEWER_REQUEST
}]
}
});export async function handler(event) {
const request = event.Records[0].cf.request;
const queryParams = new URLSearchParams(request.querystring);
const token = queryParams.get('token');
if (token) {
// Validate token (check signature, expiration, etc.)
const isValid = await validateToken(token);
if (isValid) {
// Set authentication cookie
return {
status: '302',
headers: {
'location': [{ value: '/' }],
'set-cookie': [{ value: `auth_token=${token}; Secure; HttpOnly` }]
}
};
}
}
// Check existing cookie
const cookies = request.headers.cookie?.[0]?.value || '';
if (cookies.includes('auth_token=')) {
return request; // Authenticated, proceed
}
// Not authenticated, show public view or error
return request;
}// Main stack in eu-central-1
const mainStack = new MainStack(app, 'MainStack', {
env: { region: 'eu-central-1' }
});
// Web stack in us-east-1 (for Lambda@Edge)
const webStack = new WebStack(app, 'WebStack', {
env: { region: 'us-east-1' }
});
// Pass data via SSM Parameter Store, not direct referencesnpm run build# buildspec.yml
phases:
build:
commands:
- cd frontend && npm run build
- cd infrastructure && cdk deploy WebStack
- aws s3 sync frontend/out s3://${BUCKET_NAME}
- aws cloudfront create-invalidation --distribution-id ${DIST_ID} --paths "/*"