こんにちは、CX 事業本部 Delivery 部の若槻です。
先日に AWS CDK v2.118.0 がリリースされ、CloudFront Functions の L2 Construct で runtime
プロパティを設定可能になりました。
Features
- cloudfront: CloudFront Function runtime property (#28099) (9b466ae), closes #28163
当該のアップデートの Pull Request は以下になります。
このアップデートにより、AWS CDK による CloudFront Functions の構築で、新しいランタイムである JavaScript runtime 2.0 の選択がサポートされるようになりました。
CloudFront Functions のランタイムについて
CloudFront Functions が現在サポートしているランタイムは以下の 2 つです。
- JavaScript runtime 1.0
- JavaScript runtime 2.0
いずれも ECMAScript (ES) version 5.1 に準拠しているのに加え、古いランタイムである JavaScript runtime 1.0 が ES バージョン 6 から 9 の一部機能をサポートしているのに対して、新しいランタイムである JavaScript runtime 2.0 は ES バージョン 6 から 12 の一部機能に対応しています。
例えば、JavaScript runtime 2.0 は、1.0 に無い構文として以下をサポートしており、よりモダンなコードの記述が可能になっています。
async
await
const
let
() => 式
(アロー関数式)
上記のような追加の構文や機能の記述を使用した CloudFront Functions が、今回のアップデートにより AWS CDK で簡単に構成できるようになりました。
試してみた
AWS CDK で runtime
プロパティを指定して、JavaScript runtime 2.0 ランタイムの CloudFront Functions を構築してみます。
CDK ライブラリのアップグレード
AWS CDK のモジュールを v2.118.0 以上にアップグレードします。
npm i aws-cdk@latest aws-cdk-lib@latest
型定義の確認
node_modules
に生成された型定義を確認してみます。
FunctionProps には runtime
プロパティが追加されています。既定値は FunctionRuntime.JS_1_0
となっているので、JavaScript runtime 2.0 を使用する場合は明示的に設定が必要です。
node_modules/aws-cdk-lib/aws-cloudfront/lib/function.d.ts
/**
* Properties for creating a CloudFront Function
*/
export interface FunctionProps {
/**
* A name to identify the function.
* @default - generated from the `id`
*/
readonly functionName?: string;
/**
* A comment to describe the function.
* @default - same as `functionName`
*/
readonly comment?: string;
/**
* The source code of the function.
*/
readonly code: FunctionCode;
/**
* The runtime environment for the function.
* @default FunctionRuntime.JS_1_0
*/
readonly runtime?: FunctionRuntime;
}
FunctionRuntime プロパティです。2 つのランタイムがサポートされています。
node_modules/aws-cdk-lib/aws-cloudfront/lib/function.d.ts
/**
* The function's runtime environment version.
*/
export declare class FunctionRuntime {
readonly value: string;
/**
* cloudfront-js-1.0
*/
static readonly JS_1_0: FunctionRuntime;
/**
* cloudfront-js-2.0
*/
static readonly JS_2_0: FunctionRuntime;
/**
* A custom runtime string.
*
* Gives full control over the runtime string fragment.
*/
static custom(runtimeString: string): FunctionRuntime;
private constructor();
}
実装
CloudFront Functions のコードです。Add security headers to the response のテンプレートを使用しています。JavaScript runtime 2.0 で新しくサポートされた async
および const
が使用されています。
src/cloudfront-function/add-security-headers-to-the-response/index.js
async function handler(event) {
const response = event.response;
const headers = response.headers;
// Set HTTP security headers
// Since JavaScript doesn't allow for hyphens in variable names, we use the dict["key"] notation
headers['strict-transport-security'] = {
value: 'max-age=63072000; includeSubdomains; preload',
};
headers['content-security-policy'] = {
value:
"default-src 'none'; img-src 'self'; script-src 'self'; style-src 'self'; object-src 'none'; frame-ancestors 'none'",
};
headers['x-content-type-options'] = { value: 'nosniff' };
headers['x-frame-options'] = { value: 'DENY' };
headers['x-xss-protection'] = { value: '1; mode=block' };
headers['referrer-policy'] = { value: 'same-origin' };
// Return the response to viewers
return response;
}
CDK スタックのコードです。aws_cloudfront.Function
Construct で runtime
プロパティを指定して、JavaScript runtime 2.0 を使用するようにしています。
lib/cdk-sample-stack.ts
import {
aws_cloudfront,
aws_s3,
aws_s3_deployment,
aws_cloudfront_origins,
Stack,
RemovalPolicy,
Duration,
} from 'aws-cdk-lib';
import { Construct } from 'constructs';
export class CdkSampleStack extends Stack {
constructor(scope: Construct, id: string) {
super(scope, id);
// S3 バケットの作成
const websiteBucket = new aws_s3.Bucket(this, 'WebsiteBucket', {
removalPolicy: RemovalPolicy.DESTROY,
autoDeleteObjects: true,
});
// CloudFront から S3 バケットへのアクセスを許可するために、
// Origin Access Identity を作成し、S3 バケットのアクセスポリシーに追加する
const originAccessIdentity = new aws_cloudfront.OriginAccessIdentity(
this,
'OriginAccessIdentity'
);
websiteBucket.grantRead(originAccessIdentity);
// CloudFront Function の作成
const cloudFrontFunction = new aws_cloudfront.Function(
this,
'AddSecurityHeadersToTheResponseFunction',
{
code: aws_cloudfront.FunctionCode.fromFile({
filePath:
'src/cloudfront-function/add-security-headers-to-the-response/index.js',
}),
// JavaScript runtime 2.0 を指定
runtime: aws_cloudfront.FunctionRuntime.JS_2_0,
}
);
// CloudFront Destribution を作成
const distribution = new aws_cloudfront.Distribution(this, 'Distribution', {
defaultRootObject: 'index.html',
errorResponses: [
{
ttl: Duration.minutes(5),
httpStatus: 403,
responseHttpStatus: 403,
responsePagePath: '/error.html',
},
{
ttl: Duration.minutes(5),
httpStatus: 404,
responseHttpStatus: 404,
responsePagePath: '/error.html',
},
],
defaultBehavior: {
viewerProtocolPolicy:
aws_cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
origin: new aws_cloudfront_origins.S3Origin(websiteBucket, {
originAccessIdentity,
}),
// CloudFront Function と Distribution の関連付け
functionAssociations: [
{
function: cloudFrontFunction,
eventType: aws_cloudfront.FunctionEventType.VIEWER_RESPONSE,
},
],
},
});
// S3 バケットへのコンテンツのデプロイ、CloudFront Distribution のキャッシュ削除
new aws_s3_deployment.BucketDeployment(this, 'WebsiteDeploy', {
distribution,
destinationBucket: websiteBucket,
distributionPaths: ['/*'],
sources: [
aws_s3_deployment.Source.data(
'/index.html',
'<html><body><h1>Hello, World!</h1></body></html>'
),
aws_s3_deployment.Source.data(
'/error.html',
'<html><body><h1>Error!!!</h1></body></html>'
),
aws_s3_deployment.Source.data('/favicon.ico', ''),
],
});
}
}
動作確認
前述のコードを CDK デプロイにより AWS アカウントにデプロイします。
JavaScript runtime 2.0 の CloudFront Function が作成されました。
CloudFront Function を Viewer response でテスト実行すると、レスポンスの出力にセキュリティヘッダーが付与されました。
ブラウザから CloudFront Distribution に実際にアクセスをすると、レスポンスにセキュリティヘッダーが付与されていることが確認できました。
各ランタイムバージョンのコード例
JavaScript runtime 1.0 および 2.0 のコード例は以下の公式ドキュメントにまとめられています。
次のような実際によくあるユースケースのサンプルが紹介されており、とても参考になるのでぜひ合わせてご確認ください。
- レスポンスに Cache-Control ヘッダーを追加する
- Cross-Origin Resource Sharing (CORS) ヘッダーをレスポンスに追加
- Cross-Origin Resource Sharing (CORS) ヘッダーをリクエストに追加
- レスポンスにセキュリティヘッダーを追加する
- リクエストに True-Client-IP ヘッダーを追加する
- ビューワーを新しい URL にリダイレクトさせる
- index.html を追加してファイル名を含まない URL をリクエストする
- リクエストのシンプルトークンを検証する
- クエリ文字列パラメータの正規化
おわりに
AWS CDK で CloudFront Functions での JavaScript runtime 2.0 の選択がサポートされたのでご紹介しました。
CloudFront Functions は Lambda@Edge とも異なる独自ランタイムを使用しています。今までは L2 Construct では JavaScript runtime 1.0 という構文や機能が比較的貧弱なランタイムのみサポートされていたのですが、今回のアップデートによりモダンな書き方ができる 2.0 が使用可能になりました。
公式ドキュメントでも JavaScript runtime 2.0 の利用が推奨されているので、今後 AWS CDK で新しく CloudFront Functions を構築する場合は、基本的には 2.0 を選択するようにしましょう。
以上