Closed14

CloudfrontのIP制限をAWS/WAFで行う

not75743not75743

はじめに

cloudfrontではALB等のようにセキュリティグループでIP制限を行うことが出来ません。
cloudfrontでの検証をセキュアに行うため、IP制限を実施する方法を模索します

なにを使う?

AWSのウェブアプリケーションファイアウォールであるWAFを使用します。
IP制限での制限も可能です。

https://docs.aws.amazon.com/ja_jp/waf/latest/developerguide/what-is-aws-waf.html

方針

ホワイトリストにアクセスを許可したいIPを追加し、
それ以外のリクエストを拒否するようにWEBACLを作成します

not75743not75743

事前作業

これからアクセス拒否するマシン→cloudfrontのリクエストが成功することを確認しておきます。
こいつのIPからは接続できないようにこれからします

$ curl -I https://<cloudfrontドメイン>
HTTP/2 200
not75743not75743

②WEBACL作成

  • リソースタイプはcloudfrontにし、対象のディストリビューションを選択する
  • 先程設定したIPを使用するため、ルールは自身のものとし、ルールタイプをIP Setとする
  • IPセットのIPアドレスからの通信をallowとし、ブロックするIPアドレスの種類は送信元IP(ヘッダ内のものではなく)とする
  • DefaultActionはblockとする。これでルールに合致するIP以外はblockされる
  • cloudwatch logsでログを取得する場合、以下の様にする
    • ロググループ名の頭にaws-waf-logs-をつける
    • us-east-1にロググループを作成する
  • リクエストのサンプリングを有効にすると、ルールに合致したリクエスト、デフォルトアクションに該当するリクエストの詳細が表示される
not75743not75743

③動作確認

先程の端末からリクエストを送ると

$ 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です

not75743not75743

③動作確認(見た目)

ブラウザで見るとこんな感じです

not75743not75743

ルールをcloudfrontから外す

Associated AWS resourcesよりcloudfrontディストリビューションを選択し、DisassociateすればOKです
その後ルール本体、IPセットを削除します。

not75743not75743

Terraform化

ip set

  • バージニアリージョンに作成する必要があるため、デフォルトリージョンをそれ以外に設定している場合、エイリアスでリージョン指定する
  • scopeCLOUDFRONTとする。保護対象によって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"]
}

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/wafv2_ip_set

not75743not75743

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
  }
}
not75743not75743

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.

not75743not75743

ルールを外す場合

例えば検証完了してフルアクセスにする場合、

resource "aws_cloudfront_distribution" "cfront" {
// 略
-  web_acl_id = aws_wafv2_web_acl.web_acl.arn

web_acl_idを外してしまえばよいです

このスクラップは2023/06/22にクローズされました