LoginSignup
8
4

More than 1 year has passed since last update.

CloudFront Functions の活用パターン集

Last updated at Posted at 2022-05-01

はじめに

CloudFront Functions(以後CF2)は、L@Eと異なり、軽量のため、L@Eより優先して使用を検討する必要がようなので、CF2について使用パターンをまとめました。

ビューアーレスポンスは使用しなかったため、ビューアーリクエストのみのパターンになります。

CF2とL@Eの比較

1 2 3
CloudFront Functions Lambda@Edge
ランタイムサポート JavaScript(ECMAScript 5.1準拠) Node.js、Python
実行場所 218 以上の CloudFrontエッジロケーション 13 の CloudFrontリージョンのエッジキャッシュ
CloudFront トリガー ビューアリクエスト / ビューアレスポンス ビューアリクエスト / ビューアレスポンス / オリジンリクエスト / オリジンレスポンス
最大実行時間 1 ミリ秒未満 5 秒 (ビューアトリガー) / 30 秒 (オリジントリガー)
最大メモリ 2 MB 128 MB (ビューアトリガー) / 10 GB (オリジントリガー)
合計パッケージサイズ 10 KB 1 MB (ビューアトリガー) / 50 MB (オリジントリガー)
ネットワークアクセス なし あり
ファイルシステムアクセス なし あり
リクエスト本文へのアクセス なし あり
料金 無料利用枠あり。リクエストごとに課金。 無料利用枠なし。リクエストと関数の実行時間ごとに課金。
デプロイ反映時間 10秒以下 5分程度
デプロイ方法 複数を一度にデプロイ可能 1つずつデプロイ可能

CF2は、JavaScript(ECMAScript 5.1準拠)のため、constなど使用できない制限があります。下記で使用できる機能が挙げられています。

CF2の方が、軽量、デプロイ反映が早い、という点で始めに検討するとよいかと思います。

IP制限

許可したIPの場合、リクエストが通り、NGの場合403をレスポンスします

function handler(event) {
  var request = event.request;
  var clientIP = event.viewer.ip;
  // 許可するIPを指定
  var IP_WHITE_LIST = ["xxx.xxx.xxx.xxx", "xxx.xxx.xxx.xxx"];
  var allowIP = IP_WHITE_LIST.includes(clientIP);

  if (allowIP) {
    return request;
  } else {
    var response = {
      statusCode: 403,
      statusDescription: "Forbidden",
    };
    return response;
  }
}

アクセス承認

Bearer認証やBasic認証でCF2は使用できます。

Bearer認証

Bearerのトークンパラメータが成功した場合、リクエストが通り、失敗した場合、401エラーをレスポンスという処理になっています。

function handler(event) {

  var request = event.request;
  var headers = request.headers;

  var authString = "Bearer <token値>";

  if (
    typeof headers.authorization === "undefined" ||
    headers.authorization.value !== authString
  ) {
    return {
      statusCode: 401,
      statusDescription: "Unauthorized",
      headers: { "www-authenticate": { value: "Bearer" } },
    };
  }
  console.log("request-success");
  return request;
}

ローカルで認証できているか確認する場合、curlを使いましょう。

$ curl https://www.hoge.com/test/ \
  -H "Authorization:Bearer token値"

Basic認証

Basic認証のトークンパラメータが成功した場合、リクエストが通り、失敗した場合、401エラーを返すという処理になっています。

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

  // echo -n user:pass | base64
  var authString = "Basic <token値>";

  if (
    typeof headers.authorization === "undefined" ||
    headers.authorization.value !== authString
  ) {
    return {
      statusCode: 401,
      statusDescription: "Unauthorized",
      headers: { "www-authenticate": { value: "Basic" } }
    };
  }
  console.log("request-success");
  return request;
}

URLの書き換え

/test/のパスを/fuga/に書き換える

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

  if (uri.startsWith("/test/")) {
    request.uri = "/fuga/";
  }
  return request;
}

CFの代替ドメイン名 (CNAME)に記載がないホスト名は、ビューアーリクエストで書き変えることは、基本的にできません。
CNAME に複数指定するよう *.hoge.com等の対応するとできますが、それ以外の方法でホストを書き換えたい場合、L@Eのオリジンリクエストで実現できます。

サブディレクトリのドキュメントルートを指定

静的サイトをS3に構築した場合、サブドメイン名と同じS3のディレクトリをルーティングできます。

fuga.hoge.comの場合、S3のあるバケットのfugaディレクトリを指定する。

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

  var prefix = host.split(".", 1)[0];
  if (uri.startsWith("/")) {
    request.uri = "/" + prefix + uri;
  } else {
    request.uri = "/" + prefix + "/" + uri;
  }
  return request;
}

リダイレクト

URLのリダイレクト

特定のパスのみリダイレクト

/test/配下のパスは、/test/403.htmlにリダイレクトさせる

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

  if (uri.startsWith("/test/") && uri != "/test/403.html") {
    return {
      statusCode: 301,
      statusDescription: "Moved Permanently",
      headers: { location: { value: `https://${host}/test/403.html` } },
    };
  }
  return request;
}

必ずリダイレクトさせる

必ず/test/403.htmlにリダイレクトさせる

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

  if (uri != "/test/403.html") {
    return {
      statusCode: 301,
      statusDescription: "Moved Permanently",
      headers: { location: { value: `https://${host}/test/403.html` } },
    };
  }
  return request;
}

リダイレクトの場合、ホストを変えることは、もちろん可能です。

403を返す

403を返す

function handler(event) {
  var response = {
    statusCode: 403,
    statusDescription: "Forbidden",
  };
  return response;
}

wwwなしのhostをwwwにリダイレクトさせる

hoge.comをリクエストした場合、www.hoge.comにリダイレクトさせます。
CloudFrontには、元々xxx.cloudfront.netというドメインが使用されているため、そのドメインでないことを判定に含めます。

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

  if (!host.includes('cloudfront.net') && !host.startsWith('www')) {
    return {
      statusCode: 301,
      statusDescription: 'Moved Permanently',
      headers: { location: { value: `https://www.${host}${uri}` } },
    };
  }

  return request;
}

ルートディレクトリをindex.phpに指定

fuga.com/test/やfuga.com/test`の場合、index.htmlがデフォルトで表示されるようにします。

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

  if (uri.endsWith("/")) {
    request.uri += "index.html";
  } else if (!uri.includes(".")) {
    request.uri += "/index.html";
  }

  return request;
}

他のCF2の使用パターン

ドキュメントでは、使用例が豊富でした。

  • レスポンスに Cache-Control ヘッダーを追加する
  • Cross-Origin Resource Sharing (CORS) ヘッダーをレスポンスに追加
  • Cross-Origin Resource Sharing (CORS) ヘッダーをリクエストに追加
  • レスポンスにセキュリティヘッダーを追加する
  • リクエストに True-Client-IP ヘッダーを追加する
  • ビューワーを新しい URL にリダイレクトさせる
  • index.html を追加してファイル名を含まない URL をリクエストする
  • リクエストの単純なトークンを検証する

CF2のログ出力方法

ログの出力方法は、下記のドキュメントにも記載がありますが、console.log()を記述し、CloudFrontに設置し、実際に起動させる必要があります。
L@Eと異なり、ログは、us-east-1のみで出力・記録されます。

eventの構造

下記で、event構造が記載されています。
例えば、user-agentヘッダーは、request.headers["user-agent"].valueで取得できます。

参考

8
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
4