2
0

More than 3 years have passed since last update.

CloudFront FunctionsでIPアドレス制限をする CloudFormation templateの書き方例

Last updated at Posted at 2021-07-20

はじめに

CloudFront Functionsは CloudFront上で実行できる小さなFunctionで、Lambda@Edge よりも軽量な処理をちょっと行いたいときに便利そうです。
例えば、あるURLに対してIPアドレス制限をする、という用途が考えられます。
ググると色々記事もあります(例: CloudFront FunctionsでIP制限を試してみた)。
この方法は、IPアドレスを変更するたびにCloudFront Functionをデプロイしなおさないといけないので、社内のIPアドレスなどほぼ変化しないようなケースでしか使いづらいです。が、WAFを使う方法に比べて、お手軽に安くできるというメリットはあるかなと思います。

今回は CloudFormation でどう書いたら良いのか調べてみたので、書き残しておきます。

CloudFormation templateの書き方例

例としては以下のようになります。
ちょっと説明を書いておきます。

  • www.example.com への CloudFront に対する設定
  • /faq/ ページは 123.45.67.89 というIPからのみアクセスを許可
    • 他のページは、全てアクセス許可
  • CachePolicy は適当なので、用途に応じて変える必要がある
  • CacheBehaviors を追加していくことで、違うPathへの違う制限をすることができる
AWSTemplateFormatVersion: "2010-09-09"
Description: CloudFront with CloudFunction example

Parameters:
    OriginName: 
      Type: String
      Default: www.example.com

    AllowIPRegexp:
      Type: String
      Default: "^(123[.]45[.]67[.]89)$"

Outputs:
  CDNUrl:
    Description: CDN URL
    Value: !Sub "https://${CloudFrontDistrib.DomainName}/"

Resources:
  DefaultCachePolicy:
    Type: AWS::CloudFront::CachePolicy
    Properties: 
      CachePolicyConfig: 
        Name: SimpleConfig
        DefaultTTL: 3600
        MinTTL: 600
        MaxTTL: 86400
        ParametersInCacheKeyAndForwardedToOrigin:
          CookiesConfig:
            CookieBehavior: all
          EnableAcceptEncodingGzip: true
          HeadersConfig:
            HeaderBehavior: none
          QueryStringsConfig:
            QueryStringBehavior: all

  IPRestrictionFunction:
    Type: AWS::CloudFront::Function
    Properties:
      Name: IPRestriction
      AutoPublish: true
      FunctionConfig:
        Comment: IP-Restriction-Function
        Runtime: cloudfront-js-1.0
      FunctionCode: !Sub |
        function handler(event) {
          var request = event.request;
          var clientIP = event.viewer.ip;
          var regexp = new RegExp("${AllowIPRegexp}");

          if (!regexp.test(clientIP)) {
            var response = {
              statusCode: 403,
              statusDescription: "Forbidden",
              // debug用に余計なHeaderを追加してみる
              headers: {
                "x-cloudfrontfunction-version": {value: "IPRestriction-Ver1"},
                "x-ip-denied-from-cloudfront": {value: clientIP},
              }
            };
            return response;
          }

          return request;
        }

  CloudFrontDistrib:
    Type: AWS::CloudFront::Distribution
    Properties:
      DistributionConfig:
        Origins:
          -
            DomainName: !Ref OriginName
            Id: OriginGW
            CustomOriginConfig:
              OriginProtocolPolicy: "match-viewer"
              OriginSSLProtocols: [ "TLSv1.2" ]
        Comment: CloudFront distribution
        Enabled: true
        DefaultCacheBehavior:
          CachePolicyId: !Ref DefaultCachePolicy
          TargetOriginId: OriginGW
          ViewerProtocolPolicy: "redirect-to-https"
        CacheBehaviors:
          -
            PathPattern: "/faq/"
            TargetOriginId: OriginGW
            CachePolicyId: !Ref DefaultCachePolicy
            ViewerProtocolPolicy: "redirect-to-https"
            FunctionAssociations:
              - 
                EventType: viewer-request
                FunctionARN: !GetAtt IPRestrictionFunction.FunctionMetadata.FunctionARN

さいごに

最初のデプロイは数分程度かかりましたが、CloudFront FunctionのUpdateは1分くらいで終わるので、割と開発もやりやすかったです。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0