LoginSignup
0
0

More than 1 year has passed since last update.

AWS WAF v2でCloudFrontのIPアドレス制限を作成する

Last updated at Posted at 2021-10-27

この記事の目的は?

CloudFront + AWS WAFは非常に汎用性のある構成であるにも関わらずCloudFormation自動作成の記事が少なかったので、実装方法を記載します

どんなものを実装できるの?

特定のIPのみアクセス可能なCloudFrontをyamlから作成できます

構成

composition.png

注意することその1

CloudFront+WAFの構成を作る上で気をつけなければいけないのが作成順序です

CloudFrontを作ってからWAFを作って、関連付けるのではなく

WAFを作ってからCloudFrontを作って、関連付けるのが正しいです

理由:CloudFrontディストリビューションはARNでWAFを参照できますが、WAFはCloudFrontを参照する機能が無いからです

注意することその2

WAFをCloudFormationで作成する場合、CloudFormationを実行するリージョンは米国東部 (バージニア北部)us-east-1で実行して下さい

その他リージョンで実行しても失敗してしまいます

参考元:https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-wafv2-webacl.html

For CLOUDFRONT, you must create your WAFv2 resources in the US East (N. Virginia) Region, us-east-1.

作ってみた

実現したいことはこの3つ

  1. アクセスを許可させたいIP群のリストを作成する
  2. そのリストにあるIPのみアクセス可能なWAFを作成する
  3. 作成したWAFをCloudFront用コードから参照して関連付けられるよう、WAFのARNの値を出力できるようにしておく

さっそく、CloudFormationのコードをyamlで作成します

CloudFormationをyaml言語で作成

wafv2.py
AWSTemplateFormatVersion: '2010-09-09'
Description: WAF by Cloud Front
Parameters:
Resources:
  WebACL:                          # WAF本体はこの  WebACL で作成します
    Type: AWS::WAFv2::WebACL
    Properties:
      Name: WebACL_test
      Scope: CLOUDFRONT            # CloudFront用のWAFなのでScopeは CLOUDFRONT にしましょう
      DefaultAction:
        Block: {}
      VisibilityConfig:
        SampledRequestsEnabled: true
        CloudWatchMetricsEnabled: true
        MetricName: webaclcloudfront
      Rules:                       # WAFのアクセス制御の具体的な方法はこの Rules で設定します
        -
          Name: rules-proxy-test
          Priority: 0
          Action:
            Allow: {}
          Statement:
            IPSetReferenceStatement:
              Arn: !GetAtt WAFIPSet.Arn  # ここでは後述の WAFIPSet で作成したIP情報のARNを参照するようにしています
          VisibilityConfig:
            SampledRequestsEnabled: true
            CloudWatchMetricsEnabled: true
            MetricName: rules-proxy-test

  WAFIPSet:                              # アクセスを許可したいIPはこの WAFIPSet で設定します
    Type: AWS::WAFv2::IPSet
    Properties:
      Name: wafipset-test
      Scope: CLOUDFRONT                  # WebACLと同じくここもCLOUDFRONTと指定します
      IPAddressVersion: IPV4
      Addresses:                         # 許可させたいIPをこの Addresses に記載します
          - xxx.xxx.xxx.xxx/32
          - yyy.yyy.yyy.yyy/24
          - zzz.zzz.zzz.zzz/28
Outputs:
  CloudFrontWAF:
    Value: !GetAtt WebACL.Arn      # WAFのARNを CloudFrontWAF という論理名で出力して、CloudFrontから参照できるようにします

CloudFormationで読み込んだらリソースが作成されました

0.PNG

1および2を実現できました

  1. アクセスさせたいIPのリストを作成する (WAFIPSet)
  2. そのIPリストを元にIPでアクセス制御できるWAFを作る(WebACL)

1.PNG

3を実現できました

  1. 作成したWAFをCloudFront用コードから参照して関連付けられるよう、WAFのARNの値を出力できるようにしておく(CloudFrontWAF)

2.PNG

実装までにつまずいたところ

最初はStatementの設定を以下のようにしていました

          Statement:
            IPSetReferenceStatement: 
              !Ref WAFIPSet

CloudFormationにインポートしたら、以下のようなモデル検証エラーが発生

原文

Resource handler returned message: "Model validation failed (
  #/Rules/0/Priority: expected type: Number, found: String 
  #/Rules/0/Statement/IPSetReferenceStatement: expected type: JSONObject, found: String 
  #/Rules/0/VisibilityConfig/SampledRequestsEnabled: expected type: Boolean, found: String 
  #/Rules/0/VisibilityConfig/CloudWatchMetricsEnabled: expected type: Boolean, found: String 
  #/VisibilityConfig/SampledRequestsEnabled: expected type: Boolean, found: String 
  #/VisibilityConfig/CloudWatchMetricsEnabled: expected type: Boolean, found: String)" (RequestToken: f1cbb0f3-5861-59ab-ffbc-36c56447b5b0, HandlerErrorCode: InvalidRequest)

和訳

リソースハンドラーが返すメッセージ: "モデルの検証に失敗しました(
#/ Rules / 0 /優先度:期待されるタイプ:数値、検出されました:文字列
#/ Rules / 0 / Statement / IPSetReferenceStatement:期待されるタイプ:JSONObject、検出されました:文字列
#/ Rules / 0 / VisibilityConfig / SampledRequestsEnabled:期待されるタイプ:ブール値、検出:文字列
#/ Rules / 0 / VisibilityConfig / CloudWatchMetricsEnabled:期待されるタイプ:ブール値、検出:文字列
#/ VisibilityConfig / SampledRequestsEnabled:期待されるタイプ:ブール値、検出:文字列
#/ VisibilityConfig / CloudWatchMetricsEnabled:予期されるタイプ:ブール値、検出:文字列) 

エラーの原因は戻り値の指定の仕方

ちゃんとAWS公式リファレンスに書かれていました

参考元:https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-wafv2-webacl.html

参照
Refリソース名、物理ID、および範囲を含むリソースのため、次のようにフォーマットされました:name|id|scope
例:my-webacl-name|xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx|REGIONAL
Fn :: GetAtt
Arn
Web ACLのAmazonリソース名(ARN)

戻りの値は!Refではなく!GetAttで指定する必要があるようです

コードを以下のように書き直して再度CloudFormationで実行したところ、成功しました!

         Statement:
            IPSetReferenceStatement:
              Arn: !GetAtt WAFIPSet.Arn

終わりに

CloudFront+WAFというありふれた構成であるにも関わらず、その構成をCloudFormationで実現する情報がウェブにはほぼ皆無だったため、非常に難儀しました

なので今後似たような状況で苦しんでいる方々のために、なるべく最小構成でコードを作っております

今回の調査のため色々なblogを巡回しましたが、答えは最初からAWS公式リファレンスにすべて書かれており、改めてAWSドキュメントの完成度の高さに感動しました

補足

参考になったページ

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0