web-dev-qa-db-ja.com

CloudFrontのサブドメインをS3の同じ名前にマッピングするにはどうすればよいですか?

私は誰かが私を啓蒙することができれば次のことをする方法を模索しています。

例えば次のマッピングは単一のCloudFrontインスタンスで可能ですか?

feature-a.domain.com => dev-bucket/feature-a
feature-b.domain.com => dev-bucket/feature-b
staging.domain.com   => dev-bucket/staging

などなど。

使用例は、存在するS3のバケットにマップするgitブランチごとに、できるだけ多くの環境をデプロイできるようにしたい場合です。これはすべて可能でしょうか?

4
Van Nguyen

はい、可能ですが、リクエストをバケットに送信する前にリクエストパラメータを操作するために、CloudFrontのLambda @ Edge拡張機能を使用する必要があります。

この公式フォーラムの投稿 で可能な解決策の1つを説明しました。同じソリューションが以下に含まれています。

Lambda @ Edgeは、CloudFrontがHTTPリクエストまたはHTTPリクエストを処理しているときに、プログラムからHTTPリクエストまたはレスポンスにアクセスできるようにします。 HTTPトランザクションは、監視および変更してからCloudFrontに制御を返すことができるJavaScriptオブジェクトとして提示されます。

このアプリケーションでは、バケットのWebサイトホスティングエンドポイントをCloudFront構成のOriginドメイン名として使用する必要があります(つまり、ドロップダウンからバケットを選択しないでください-適切な「s3-website」ホスト名を使用して入力してください)そして実際にそれを転送することはありませんが(それを読み取ってから、パスと一緒に操作します)、さらにはOriginに転送するためにHostヘッダーをホワイトリストに登録する必要があります。 、通常、これをS3オリジンに転送しても意図したとおりに機能しません...読み取りと操作ができるように、CloudFrontにホワイトリストに登録する必要があります。

次のLambda関数をOrigin Requestトリガーとして設定します。このトリガーは、CloudFrontキャッシュがチェックされてキャッシュミスが発生した後、リクエストがオリジンサーバーに送信される前に発生します(S3)。

'use strict';

// https://serverfault.com/a/930191/153161
// if the end of incoming Host header matches this string, 
// strip this part and prepend the remaining characters onto the request path,
// along with a new leading slash (otherwise, the request will be handled
// with an unmodified path, at the root of the bucket)

// set this to what we should remove from the incoming hostname, including the leading dot.

const remove_suffix = '.example.com';

// provide the correct Origin hostname here so that we send the correct 
// Host header to the S3 website endpoint
// this is the same value as "Origin domain name" in the cloudfront distribution configuration

const Origin_hostname = 'example-bucket.s3-website-us-east-1.amazonaws.com';

exports.handler = (event, context, callback) => {
  const request = event.Records[0].cf.request;
  const headers = request.headers;
  const Host_header = headers.Host[0].value;

  if(Host_header.endsWith(remove_suffix))
  {
    // prepend '/' + the subdomain onto the existing request path ("uri")
    request.uri = '/' + Host_header.substring(0,Host_header.length - remove_suffix.length) + request.uri;
  }

  // fix the Host header so that S3 understands the request
  // we have to do this even if the above if() didn't match
  headers.Host[0].value = Origin_hostname;

  // return control to CloudFront with the modified request
  return callback(null,request);
};

CloudFrontがエラー応答をキャッシュしないように、 エラーキャッシュの最小値TTLを0 に設定することも忘れないでください。これは、キャッシュ動作設定のmin/default/max TTLとは別の設定です。デフォルトは5分です。これは理にかなっていますが、この動作を予期しないとトラブルシューティングが複雑になります。


Lambda @ Edge関数は、v6.10または v8.10 Node.jsランタイム環境を使用できるようになりました。上記の例は、もともとv6.10用に作成されたものですが、v8.10ではハンドラーに追加のオプションがあるため、どちらのランタイムとも互換性があります。非同期/待機を使用したり、Promiseを直接返したり、上記のように記述したりできます。コールバックインターフェイスを使用します。

2