ロカオプ技術ブログ

株式会社ロカオプの技術ブログです。

CloudFront Functionsを使ってLambdaで元のHostヘッダを取得する方法

はじめに

株式会社ロカオププロダクト開発部、縣(@agata)です。

CloudFront経由でAPI Gateway/Lambdaが呼び出される場合、Lambda側で元のHostヘッダーの値が取得できません。この問題はCloudFront Functionsを使うことで解消できるのでその方法をご紹介します。

CloudFrontはHostヘッダーを渡さない

CloudFrontでは独自ドメインを10個まで設定することができます。またワイルドカードドメイン+証明書を使うこともできます。

複数のドメインをCloudFrontに設定しつつAPI Gateway/Lambdaに処理を移譲していた場合、どのホスト名でリクエストされたのか知りたい場合があります。例えば、サブドメインによって返すコンテンツが変わるようなCMSやSaaSサービスなどが考えられます。

しかし、CloudFrontはオリジンへのリクエストを行う際にHostヘッダーをCloudFront自体に書き換えてしまうため、Lambda側では元のHostヘッダーの取得ができません。

元のHostがLambdaからはわからなくなる

筆者もホスト名に応じてコンテンツを切り替えるサービスを開発していてこの問題に気が付きました。

CloudFlont Functionsを使って元のHostヘッダーを退避する

そこで取った作戦が「CloudFlont Functionsを使ってHostヘッダーを退避する」です。

CloudFront Functionsは2021年から一般提供が開始されたCloudFrontのエッジロケーションでJavaScriptが実行できるソリューションです。

以前よりLambda@Edgeを使ったヘッダーの書き換えなど行われていましたが、CloudFront Functionsを使用することでCloudFrontだけで完結して同様の処理が行なえます。

実装は簡単でCloudFront FunctionsでHostヘッダーをOrigin-Hostヘッダーにコピーするような関数を定義します。

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

  // Hostヘッダーの値をOrigin-Hostヘッダーにコピーする
  headers['origin-host'] = {value: headers['host'].value};

  return request;
}

次に作成した関数をCloudFrontのディストリビューションのビヘイビアで関連付けます。

CloudFrontのビヘイビアで関数を関連付けする

最後にLambda側でコピーしたヘッダーを取得すれば完了です。これで元のホストヘッダーの値が取得できるようになりました。

// 元のホスト名を取得
const host = event.headers['Origin-Host'];
console.log({host});

元のHostが取得可能に!

注意点

CloudFrontでキャッシュの設定を行う場合、ディストリビューションのビヘイビアでHostヘッダによるキャッシュの出しわけを適切に設定しておきましょう。この設定をしないとドメインごとにコンテンツを切り替えてキャッシュすることができず、意図しないコンテンツが返却されるという事故が起きる可能性があります。 (キャッシュしない設定の場合はこの設定は不要です)

おわりに

5年ぶりぐらいに技術ブログを書く気がしますが、今後はロカオプの開発現場の状況が伝わるように定期的に発信していきたいと思っています。

現在、ロカオプでは開発エンジニアを募集しています。ロカオプの開発環境などについて知りたい方は「ロカオプを支える技術」をご覧ください。