CloudfrontのIP制限をAWS/WAFで行う
はじめに
cloudfrontではALB等のようにセキュリティグループでIP制限を行うことが出来ません。
cloudfrontでの検証をセキュアに行うため、IP制限を実施する方法を模索します
なにを使う?
AWSのウェブアプリケーションファイアウォールであるWAFを使用します。
IP制限での制限も可能です。
方針
ホワイトリストにアクセスを許可したいIPを追加し、
それ以外のリクエストを拒否するようにWEBACLを作成します
事前作業
これからアクセス拒否するマシン→cloudfrontのリクエストが成功することを確認しておきます。
こいつのIPからは接続できないようにこれからします
$ curl -I https://<cloudfrontドメイン>
HTTP/2 200
①許可したいIPをIPセットに追加
リージョンを選択する項目がありますが、保護の対象がcloudfrontの場合はGlobal(CloudFront)
を選択します
②WEBACL作成
- リソースタイプはcloudfrontにし、対象のディストリビューションを選択する
- 先程設定したIPを使用するため、ルールは自身のものとし、ルールタイプを
IP Set
とする - IPセットのIPアドレスからの通信を
allow
とし、ブロックするIPアドレスの種類は送信元IP(ヘッダ内のものではなく)とする - DefaultActionは
block
とする。これでルールに合致するIP以外はblockされる - cloudwatch logsでログを取得する場合、以下の様にする
- ロググループ名の頭に
aws-waf-logs-
をつける -
us-east-1
にロググループを作成する
- ロググループ名の頭に
- リクエストのサンプリングを有効にすると、ルールに合致したリクエスト、デフォルトアクションに該当するリクエストの詳細が表示される
③動作確認
先程の端末からリクエストを送ると
$ curl https://<cloudfrontドメイン>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
<TITLE>ERROR: The request could not be satisfied</TITLE>
</HEAD><BODY>
<H1>403 ERROR</H1>
<H2>The request could not be satisfied.</H2>
<HR noshade size="1px">
Request blocked.
We can't connect to the server for this app or website at this time. There might be too much traffic or a configuration error. Try again later, or contact the app or website owner.
<BR clear="all">
If you provide content to customers through CloudFront, you can find steps to troubleshoot and help prevent this error by reviewing the CloudFront documentation.
<BR clear="all">
<HR noshade size="1px">
<PRE>
Generated by cloudfront (CloudFront)
Request ID: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
</PRE>
<ADDRESS>
</ADDRESS>
</BODY></HTML>
このように弾かれることがわかります。
ステータスコードは403です
③動作確認(見た目)
ブラウザで見るとこんな感じです
ログについて
なにも設定を追加しない場合、ログはallow,blockのすべてのフィールドを出力するようです。
必要な情報に絞るようにフィルターを設定するのがよいでしょう。
また、ログのマスキングもできるようです。
参考
ルールをcloudfrontから外す
Associated AWS resources
よりcloudfrontディストリビューションを選択し、Disassociate
すればOKです
その後ルール本体、IPセットを削除します。
Terraform化
ip set
- バージニアリージョンに作成する必要があるため、デフォルトリージョンをそれ以外に設定している場合、エイリアスでリージョン指定する
-
scope
はCLOUDFRONT
とする。保護対象によってREGIONAL
と選択になる。
provider "aws" {
alias = "virginia"
region = "us-east-1"
}
variable "allow-ip" {
type = string
}
resource "aws_wafv2_ip_set" "ipset" {
provider = aws.virginia
name = "allow-ip"
description = "allow ip set"
scope = "CLOUDFRONT"
ip_address_version = "IPV4"
addresses = ["${var.allow-ip}/32"]
}
webacl
- こちらもバージニアリージョン指定
-
ip_set_reference_statement
で作成したIPセットを使用 - ログを見る場合は
visibility_config
の設定をする
resource "aws_wafv2_web_acl" "web_acl" {
provider = aws.virginia
name = "only-myip"
description = "A sample Web ACL that blocks all traffic except for a allow IP set"
scope = "CLOUDFRONT"
default_action {
block {}
}
rule {
name = "allow_ips_in_ip_set"
priority = 1
action {
allow {}
}
statement {
ip_set_reference_statement {
arn = aws_wafv2_ip_set.ipset.arn
}
}
visibility_config {
sampled_requests_enabled = false
cloudwatch_metrics_enabled = false
metric_name = "sample"
}
}
visibility_config {
cloudwatch_metrics_enabled = false
metric_name = "sample_web_acl_metric"
sampled_requests_enabled = false
}
}
cloudfrontディストリビューション
最後にディストリビューション側でweb aclを指定します。
resource "aws_cloudfront_distribution" "cfront" {
// 略
web_acl_id = aws_wafv2_web_acl.web_acl.arn
注意として、wafv2_web_acl_associationはcloudfrontでは使用できないようです。
NOTE on associating a WAFv2 Web ACL with a Cloudfront distribution:
Do not use this resource to associate a WAFv2 Web ACL with a Cloudfront Distribution. The AWS API call backing this resource notes that you should use the web_acl_id property on the cloudfront_distribution instead.
ルールを外す場合
例えば検証完了してフルアクセスにする場合、
resource "aws_cloudfront_distribution" "cfront" {
// 略
- web_acl_id = aws_wafv2_web_acl.web_acl.arn
web_acl_id
を外してしまえばよいです