CloudFront Functionsでブラックリストを作成してみた

2023.12.08

この記事はアノテーション株式会社 AWS Technical Support Advent Calendar 2023 | Advent Calendar 202X - Qiita 8日目の記事です。

こんにちは!アノテーションの八木谷です。 費用的に WAF は入れられない、、、でも CloudFront にきた不審な IP からのアクセスはブロックしたいという時に使ってみてください。

CloudFront Functions または Lambda@Edge を使ってCloudFront で IP 制限を行うことができますが、今回は CloudFront Functions で対応していきます。

構成

今回は CloudFront + S3 という構成にしていますが、CloudFront + ALB + EC2 などの CloudFront を使った他の構成でも利用できます。

環境準備

S3バケット作成

まず、CloudFront のオリジンとして使用する S3 バケットを作ります。

下記の設定で、作成をしていけば大丈夫ですが、バケット名は一意である必要があるので注意してください。

また、CloudFront からのみのアクセスを許可するため、パブリックアクセスをブロックします。

  • AWSリージョン:アジアパシフィック(東京) ap-northeast-1
  • バケットタイプ:汎用
  • オブジェクト所有者:ACL無効(推奨)
  • このバケットのブロックパブリックアクセス設定:パブリックアクセスをすべてブロック

S3 バケットの作成が終わったら、index.html を用意して配置しておきます。

今回は ブラックリストに入っている IP からアクセスがあった際は index.html が見えず、ブラックリストに入っていない IP からアクセスがあった際は index.html が見えていればいいので簡単に下記の内容にします。

<html>
blacklist test
</html>

CloudFront 作成

CloudFront から S3 へのアクセスを許可するために Origin Access Control(OAC) を作成するので、 Origin access control settings ( recommended ) を選択し、コントロール設定を作成を押下してください。

今回、設定は下記のように行いますが状況に合わせて適宜設定してください。

  • オリジンドメイン:作成した S3 バケット
  • オリジンアクセス:Origin access control settings ( recommended )
  • ビューワープロトコルポリシー: HTTP and HTTPS
  • 許可された HTTP メソッド:GET,HEAD
  • ビューワーのアクセスを制限する:No
  • キャッシュキーとオリジンリクエスト:Cache policy and origin request policy ( recommended )
  • キャッシュポリシー:CachingOptimized
  • オリジンリクエストポリシー:UserAgentRefrerHeaders
  • ウェブアプリケーションファイアウォール( WAF ):セキュリティ保護を有効にしないでください。
  • 料金クラス:すべてのエッジロケーションを使用する( 最高のパフォーマンス )

 

バケットポリシー設定

作成した S3 バケット選択しアクセス許可タブにあるバケットポリシーの編集を押下して、CloudFront の設定からのアクセスのみ許可する設定を行います。

AWS 公式ドキュメント にあるバケットポリシーを使用します。

今回は読み取りのみ行えれば良いので、下記のポリシーを設定します。

{
    "Version": "2012-10-17",
    "Statement": {
        "Sid": "AllowCloudFrontServicePrincipalReadOnly",
        "Effect": "Allow",
        "Principal": {
            "Service": "cloudfront.amazonaws.com"
        },
        "Action": "s3:GetObject",
        "Resource": "arn:aws:s3:::<S3 bucket name>/*",
        "Condition": {
            "StringEquals": {
                "AWS:SourceArn": "arn:aws:cloudfront::<AWS アカウント ID>:distribution/<CloudFront distribution ID>"
            }
        }
    }
}

これで環境準備が整ったので、ブラックリストを作成する前に CloudFront 経由で S3 バケットに配置した index.html が見えるか確認します。

xxxxxxxxxx.cloudfront.net/index.html ( ディストリビューション名/index.html ) という URL でアクセスし、S3 バケットに配置した index.html の内容が表示されれば OK です。

CloudFront Functions でブラックリスト作成

ブラックリスト作成

次に CloudFront Functions を使ってブラックリストを作成していきます。

CloudFront のコンソールの左ペインにある「関数」が CloudFront Functions なので、そこから「関数を作成」を押下し、関数コードに下記のコードをペーストして変更を保存してください。

function handler(event) {
    var request = event.request;
    var clientIP = event.viewer.ip;
    // アクセス拒否するIPを設定
    var IP_BLACK_LIST = [
     'xxx.xxx.xxx.xxx',
     'xxx.xxx.xxx.xxx',
    ];
    // クライアントIPが、アクセス拒否するIPに含まれていればtrueを返す
    var isRejectedIp = IP_BLACK_LIST.includes(clientIP);

    if (isRejectedIp) {
        var response = {
           statusCode: 403,
            statusDescription: 'Forbidden',
        }

        // trueの場合はViewer に対してレスポンスを返す
        return response;
    } else {
        // falseの場合はオリジン側へリクエストを渡す
        return request;
    }
}

その後、発行タブから「関数の発行」を押下し、画面下部の「関連付けを追加」から下記の情報で設定します。

  • Distribution:作成した CloudFront
  • Event Type:Viewer Request
  • Cache behavior:任意のビヘイビア

挙動確認

ブラックリストに追加した IP から CloudFront のディストリビューションドメイン名にアクセスして アクセスが拒否されていれば OK です。

アクセスができてしまった場合は、IPv6 を使用している可能性があるのでコードの IP_BLACK_LIST に IPv6 の IP を入れてみてください。

アノテーション株式会社について

アノテーション株式会社は、クラスメソッド社のグループ企業として「オペレーション・エクセレンス」を担える企業を目指してチャレンジを続けています。「らしく働く、らしく生きる」のスローガンを掲げ、様々な背景をもつ多様なメンバーが自由度の高い働き方を通してお客様へサービスを提供し続けてきました。現在当社では一緒に会社を盛り上げていただけるメンバーを募集中です。少しでもご興味あれば、アノテーション株式会社WEBサイトをご覧ください。