CloudfrontのIP制限をAWS/WAFで行う
はじめに
CloudFrontではALB等のようにセキュリティグループでIP制限を行うことが出来ません。
CloudFrontでの検証をセキュアに行うため、IP制限をWAFで実現します。
プロビジョニングはTerraformでおこないます。
環境
Terraform 1.4.6
方針
IP Setへ許可したいIPを追加し、
それ以外のリクエストを拒否するようなWeb Aclを作成します。
前提
- CloudFrontがデプロイ済み
- 検証用マシン→CloudFrontのリクエストが成功することを確認しておきます。
検証用マシンのIPを拒否するように設定します。
$ curl -I https://<cloudfrontドメイン>
HTTP/2 200
検証
IP Set
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"]
}
scope
がCLOUDFRONT
である場合、バージニアリージョン(us-east-1)に作成する必要があります。
そのためのaliasです。
Web Acl
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
}
}
こちらもバージニアリージョンである必要があります。
ログ,サンプリングの設定が必要である場合、visibility_config
を設定します。
CloudFrontディストリビューション
resource "aws_cloudfront_distribution" "cfront" {
// 略
web_acl_id = aws_wafv2_web_acl.web_acl.arn
CloudFrontディストリビューション側でさきほど作成したWeb Aclを指定します。
また、aws_wafv2_web_acl_association
はCloudFrontでは使用出来ません。
気をつけましょう。
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.
動作確認
先程の検証用マシンからリクエストを送ると
$ 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>
このようにWAFに弾かれます。
ステータスコードは403ですね。
ブラウザでの見た目はこんな感じです。
ルールを外す場合
例えば検証完了してフルアクセスにする場合、
resource "aws_cloudfront_distribution" "cfront" {
// 略
- web_acl_id = aws_wafv2_web_acl.web_acl.arn
このようにweb_acl_id
を外してしまえばよいです
参考
こちらの記事を参考にさせていただきました。
Discussion