はじめに
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分くらいで終わるので、割と開発もやりやすかったです。