サーバーレス構成でのBasic認証実現方法をご紹介!😎CloudFrontとLambda@Edgeのテクニックを解説🚀

サーバーレス構成でのBasic認証実現方法をご紹介!😎CloudFrontとLambda@Edgeのテクニックを解説🚀

こんにちは!

サーバーレスの構成の場合に、Basic 認証の実現方法は悩みどころだと思います。

EC2 インスタンスを立てていれば、Apache の httpd.conf などで簡単に実現できるところですが、サーバーレスの構成の場合は基本的にウェブサーバーのモジュールを使用できません。(ECS でしたら Docker コンテナーで Apache を制御して実現できそうですが)

本記事では、JavaScript のソースコードを交え実装方法をご紹介いたします。

想定する読者

  • サーバーレスでのアプリケーション構築を行っているヒト
  • CloudFront と LambdaEdge で Basic を実現したいヒト

はじめに

CloudFront を導入しているのが前提

本記事では、CloudFront と LambdaEdge を使用してBasic 認証を実現する方法をご紹介します。

アプリケーションの HTML/CSS 提供には CloudFront の導入を推奨

CloudFront を導入することで下記のような恩恵を受けることができます。まだ導入したことがないという方は、ぜひこの機会に導入を検討しましょう。

  • AWS WAF の導入が容易
  • CDN によるコンテンツキャッシュの提供
  • Origin の処理を実行せずにキャッシュでコンテンツを返却可能となるので導入方法によってはコスト削減(Fargateなどの実行をその都度させなくて済みます)
  • Alias レコードで Route53 と接続可能となり、名前解決のパフォーマンス向上

CloudFront の魅力はまだまだありますが、そろそろ本題に移ろうと思います😎

Lambda@Edge の構築方法を解説

まず、下記のソースコードを NodeJs 12.x のランタイムを持つ Lambda 関数へデプロイします。注意点としては下記です。

  • Lambda@Edge は東京リージョンでは扱えない
  • バージニアリージョンで構築することが必要です
'use strict';
module.exports.handle = (event, context, callback) => {
  const request = event.Records[0].cf.request;
  const headers = request.headers;

  const authUser = 'username'; // Basic認証のユーザー名
  const authPass = 'password'; // Basic認証のパスワード

  const authString = 'Basic ' + new Buffer(authUser + ':' + authPass).toString('base64');

  if (typeof headers.authorization == 'undefined' || headers.authorization[0].value != authString) {
    const body = 'Unauthorized';
    const response = {
      status: '401',
      statusDescription: 'Unauthorized',
      body: body,
      headers: {
        'www-authenticate': [{key: 'WWW-Authenticate', value: 'Basic'}]
      },
    };
    callback(null, response);
  }

  callback(null, request);
}

Lambda 関数の構築が終わったら、次は構築した Lambda 関数ををCloudFront の Viewer Request(Lambda@Edge)へデプロイします。これで Basic 認証の実装は完了です。

CloudFront で Lambda@Edge の反映を確認

指定の CloudFront の Behavior の設定を確認しましょう。先ほどデプロイしたLambda@Edge の ARN が Viewer Request へ設定されているはずです。

複数のCloudFrontへLambdaEdgeをデプロイするには?

Basic 認証などの汎用的な処理は、1 つの関数のみ実装し使いまわしたいですよね。実現方法は至ってシンプルです。

  1. Lambda@Edge の ARN のテキストをコピー
  2. 指定の CloudFront の Viewer Request へ個別に設定

補足として、Lambda 関数のコンソールで 1 度のデプロイで指定できる CloudFront は 1 つのみです。そのため、私たちは ARN をコピーしてCloudFront へ貼り付ける方法が楽ではないかと感じますが、お好きな方で対応ください。(CloudFormation でデプロイを自動化することも可能ですので合わせて検討ください)

まとめ

Lambda@Edge は、CloudFront の Edge ロケーションに最も近い場所で実行されるので、ちょっとした処理を加えるなら手軽でかつパフォーマンスに優れている手法ではと感じます。(適宜 Lambda のスペックを下げてコスト節約は必ずしておきましょう)

他にもまだまだ活用方法ありますが、他の記事で紹介したいと思います!

サーバーレス開発に関してお悩みの方は、気軽にご相談ください。