🏌️‍♂️

CloudFrontのLambdaで特定パスのIP制限を行う話

に公開

まえがき

はじめまして!株式会社ウェイブで国内向けのコミック配信サイト ComicFesta の開発をしてるぴらふです。

今回やりたいこと

CloudFrontに付随するLambdaを使ってパスの制御をしていたのですが、新たに試験フェーズのパスを追加することになりました。ただし、このパスは社内の特定のユーザーしか閲覧できない状態にする必要がありました。

「IP制限をかけられないか?」という話になり、CloudFrontのLambda@Edgeで対応できそうだったので実装してみました。

CloudFrontのLambda@EdgeでIP制限

今回制限をかけたいパスは hoge/:id/huga です。このパスにアクセスできるのは、特定のIPアドレスからのみとしたかったので、Lambda@EdgeでIPフィルタリングを実装しました。

実装方法

  • IPアドレスのリストを定義

  • リクエスト時にアクセス元IPを取得

  • IPが許可リストに含まれているか判定

  • 許可されていなければ403エラーを返す <- 必須ではない

'use strict';

exports.handler = async (event) => {
    const request = event.Records[0].cf.request;
    const headers = request.headers;
    const clientIP = headers['x-forwarded-for'][0].value.split(',')[0].trim();
    
    // 許可するIPリスト
    const allowedIPs = ["192.0.2.1", "192.0.2.2"];
    
    if (!allowedIPs.includes(clientIP)) {
        return {
            status: '403',
            statusDescription: 'Forbidden',
            body: 'Access Denied'
        };
    }
    
    return request;
};

最初、許可するパスのリストを配列として持って includes で検索していたのですが、hoge/:id/huga のようなパスパラメータを含む場合には includes では対応できませんでした。
そのため、許可するパスを正規表現で管理し、マッチングを行うようにしました。

const allowedPaths = [/^\/hoge\/\d+\/huga$/];
if (!allowedPaths.some(regex => regex.test(request.uri))) {
    return {
        status: '403',
        statusDescription: 'Forbidden',
        body: 'Access Denied'
    };
}

さいご

CloudFront + Lambda@Edgeで柔軟な制御ができるので、今後も色々なユースケースで活用できそうです。

「インフラは難しい」と思っていたけど、触ってみると理解が深まりました。
同じように悩んでいる人がいたら、「まずは手を動かしてみること」をおすすめします!

wwwave's Techblog

Discussion