⚙️

【CloudFront】Basic認証を実装したい

2025/01/03に公開

CloudFront に Basic 認証をかけたーーい!

ということで、

S3 がオリジンの CloudFront で公開している WEB アプリに Basic 認証をかけます。

Terraformを使って設定していきます

・バージョン

$ terraform providers -version
Terraform v1.4.2
on linux_amd64
+ provider registry.terraform.io/hashicorp/aws v4.67.0

実装方針

https://dev.classmethod.jp/articles/apply-basic-authentication-password-with-cloudfront-functions/

上記を見ると、CloudFront Functions で簡単に実装できるみたいです。

CloudFront Functions とは?

まずは、デフォルトディレクトリインデックスの実装に必要なCloudFront Functionsについて。

特定のイベントタイプに対して、事前に定義している JavaScript の関数を実行できる機能のこと。

イベントタイプには2種類あり、

  • ビューワーリクエスト:ビューワーからリクエストを受信したとき
  • ビューワーレスポンス:ビューワーにレスポンスを返す前

リクエスト(レスポンス)ヘッダーの操作やリダイレクト処理などを実現できます。

公式ドキュメントは ↓ です。目を通してみるといいと思います

https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/cloudfront-functions.html

CloudFront Functions の料金

公式サイトより、

100 万件の呼び出しあたり 0.10 USD です (1 回の呼び出しごとに 0.0000001 USD)。

また、無料枠として

各月 2,000,000 件の CloudFront Function 呼び出し

が設けられています。

実装

事前準備

Basic 認証では、

ブラウザから、ユーザ名とパスワードをコロン ":" でつなぎ Base64 でエンコードして送信します。

Cloudfront Fuctions で送信された文字列(認証情報)が正しいか判断します。

そのため、Base64 でエンコードされた文字列を用意しておき、JavaScript 内で判定する際に使用します。

今回は、

ユーザ名:hisui

パスワード:hisuipw

具体的には下記コマンドでエンコードされた文字列を用意します

$ echo -n "hisui:hisuipw" | base64
aGlzdWk6aGlzdWlwdw==

この文字列を次の Cloudfront Fuctions で使用します

CloudFront Functions

CloudFront Functions で実行する関数はこちらのコードをそのまま使います

js ファイルを作成し、tf ファイルから参照するようにします。

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

  // echo -n user:pass | base64
  var authString = "Basic aGlzdWk6aGlzdWlwdw==";

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

  return request;
}

authString にユーザー名, パスワードを base64 でエンコードしたものを指定し、

認証情報を送信していないもしくは、誤った認証情報を送信しているときに 401 を返します。

ヘッダーの"www-authenticate" に"Basic"を指定し、Basic 認証を使うとブラウザに伝えます

つまり、

認証情報を送信していない初めのリクエストに対して 401 と Basic 認証を使うことを伝えます。

2回目以降は送られてきた認証情報を判定し、

・あっている場合は、認証を通し、

・空欄もしくは間違っている場合は再度 Basic 認証でユーザー名とパスワードをききます

詳しく知りたい方は下記 2 つをご覧ください

https://atmarkit.itmedia.co.jp/ait/articles/1608/10/news021.html

https://qiita.com/KWS_0901/items/29963df6625af3e3fd07

Terraform

resource "aws_cloudfront_distribution" "main" {

...

  default_cache_behavior {
   ...

    # CloudFront Functionsの紐づけ
    function_association {
      event_type   = "viewer-request"
      function_arn = aws_cloudfront_function.main.arn
    }
  }

  ...
}

...

# CloudFront Functions
resource "aws_cloudfront_function" "main" {
  name    = "function"
  runtime = "cloudfront-js-1.0"
  comment = "Basic認証"
  publish = true
  code    = file("./CloudFront_Functions/function.js")
}

aws_cloudfront_distribution > default_cache_behavior ブロック内で CloudFront Functions を紐づけていきます

プロパティ 説明
event_type どのイベントタイプで実行するか viewer-request に対して関数を実行します
function_arn 後ほど定義する CloudFront Functions の ARN を指定します

aws_cloudfront_function にて、CloudFront Functions を定義します。

プロパティ 説明
name CloudFront Functions の名前
runtime ランタイム。2023/07 現在、cloudfront-js-1.0 のみ指定可能
comment コメント。
publish 関数をデプロイするかどうか。デフォルトは true。 テストなどをしたい方はデプロイしない(false) ことも可能。
code 関数のソースコード。先ほど作成した js ファイルを相対パスで指定。

plan , apply

$ terraform plan
$ terraform apply -auto-approve

ダウンタイムはなかったと思います。。。

動作確認

CloudFront のドメインにアクセスして、下記のように Basic 認証が表示されます。

ここで、

ユーザ名:hisui

パスワード:hisuipw

を入力し、認証できれば OK です!

参考記事

https://dev.classmethod.jp/articles/apply-basic-authentication-password-with-cloudfront-functions/

https://ja.wikipedia.org/wiki/Basic認証

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudfront_distribution

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudfront_function

Discussion