AWSに静的なwebサイトをホストする場合、S3 + Cloudfrontで構成されることが多いと思います。
また現在トレンドのサーバレスにおいて、フロントを担う部分にS3 + Cloudfrontを用いて
Reactアプリケーションをホストするといったことも多くあります。
そこで今回は他のサービスは使用しないで簡単にIP制限を実現できる方法を紹介しようと思います。
IP制限は実現したいけどそこまで手間はかけたくない・他のサービスを使うのは面倒だから手軽に実装したい 方向けの記事になります。
1.S3のバケットポリシーによるIP制限(S3のみの場合)
こちらは、バケットポリシーのCondition
エレメントにIPを登録する方法です。
NotIpAddress
を指定することで記述したIPアドレスからの通信を制限します。
逆にIpAddress
を指定することで、そのIPからのみ通信を受け付けます。
{
"Version": "2008-10-17",
"Id": "SampleId",
"Statement": [
{
"Sid": "1",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::bucket-name/*",
"Condition": {
"NotIpAddress": {
"aws:SourceIp": "xxx.xxx.xxx.xxx/xx"
}
}
}
]
}
2.Cloudfront FunctionsによるIP制限(Cloud Frontを使用する場合)
こちらはCloudfront FunctionsにJavaScriptによる処理を記述し、エッジロケーションで実行されるIP制限になります。
注意点として、エッジロケーションで実行されるため、実行の最大許容時間がシビアになります。
許容時間に近づくと関数がスロットリングされることもあるため、注意が必要です。
より重い処理を実行する場合は、Lambda@Edgeの使用をおすすめします。
こちら がCloudFront FunctionsとLambda@Edgeの比較になります。
下記は他サイトを参考にさせていただき、Basic認証も一緒に組み込んだものになります。
var IP_WHITE_LIST = [
'xxx.xxx.xxx.xxx'
];
var authString = "Basic xxxxxxxxxx";
function handler(event) {
var request = event.request;
var clientIP = event.viewer.ip;
var headers = request.headers;
var isPermittedIp = IP_WHITE_LIST.includes(clientIP);
if (
typeof headers.authorization === "undefined" ||
headers.authorization.value !== authString
) {
return {
statusCode: 401,
statusDescription: "Unauthorized",
headers: { "www-authenticate": { value: "Basic" } },
};
}
if (isPermittedIp) {
return request;
} else {
var response = {
statusCode: 403,
statusDescription: 'Forbidden',
}
return response;
}
}
まとめ
今回は他サービスを導入せずIP制限を実装しましたが、CloudFront Functionsのようにエッジロケーションで簡単な処理を実行できてしまうのは、ユーザーへのレスポンスも低レイテンシで返すことができ、オリジンへ処理が集中してしまうことも少ないという点でとても魅力的です。
今後IOTの普及が後押しになり、エッジコンピューティングの分野がより充実していくことに期待したいですね。
参考記事