20
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

CloudFormationからのWAFの設定(CloudFront/APIGateway)

Last updated at Posted at 2019-12-25

はじめに

AWSでサーバレスなアーキテクチャを採用していて、 各エンドポイント(CloudFront や API Gateway)にIP制限をかけたい場合 AWS WAF を用いることが多いかと思います。
この記事では、CloudFormation から各リソースと WAF のリソースを生成する際にハマりポイントが多かったのでまとめてみました。

AWS::WAF と AWS::WAFRegional

まずハマりやすいのが、この2つのリソースタイプがあること。
設定できるリソースやパラメータにあまり違いはないのですが、使い分けとしては、リージョンを持つサービスに紐づけるか、リージョンを持たないサービス(CloudFront)に紐づけるか、でどちらを選択するか決まります。

  • AWS::WAFRegional → API Gateway, ALB, etc...
  • AWS::WAF → CloudFront

と考えておけばOKだと思います。(これを逆にすると権限のエラーで失敗します。)

AWS WAF と AWS WAF Classic

この2つの違いも初見の人は注意が必要です。
AWS WAF は2019年11月にアップデートされていて、コンソールからサービスを利用する場合、はじめに新バージョンのサービスが表示されます。
旧バージョンの AWS WAF を利用する場合、左部メニューにこっそりある Switch to AWS WAF Classic をクリックすると切り替わります。
image.png

ここでハマりどころなのが、 CloudFormation のリソースタイプの AWS::WAFAWS::WAFRegional は、どちらも旧バージョン(AWS WAF Classic)のリソースを作成するものであるということです。
AWSサポートに確認したわけではないので確かではありませんが、現時点(2019年12月時点)では、CloudFormation から新バージョンの AWS WAF のリソースを生成することはできなそうです。(今後対応されそう)

template ファイル

今回、実際に CloudFront と API Gateway それぞれに紐づいた AWS WAF (Classic) を CloudFormation から生成しました。
その際、template の記述に関しても注意すべき点があったので、 コメントを追記した template.yaml を載せておきます。

共通

IP制限を行う際に、 WebACL + Rule + IPSet のリソースをセットで使用するのは、 AWS::WAFAWS::WAFRegional も同様。

AWS::CloudFront + AWS::WAF パターン

AWS::WAF の場合は、 CloudFront のリソース側から紐付けを行います。

template.yaml(CloudFront)
Parameters:
  AppName:
    Type: String
  AllowedIP:
    Type: String

Resources:
  MyDistribution:
    Type: AWS::CloudFront::Distribution
    Properties:
      # 〜その他のプロパティは省略〜
      DistributionConfig:
        WebACLId: !Ref MyWebACL #紐付けはここで行う

  # AWS::WAF の場合、リソースの紐付けに WebACLAssociation は使用しない

  MyWebACL:
    Type: AWS::WAF::WebACL
    Properties:
      Name: !Sub ${AppName}WebACL #ハイフンやアンスコは使用不可
      DefaultAction:
        Type: BLOCK
      MetricName: !Sub ${AppName}WebACL
      Rules:
        -
          Action:
            Type: ALLOW
          Priority: 1
          RuleId: !Ref MyRule

  MyRule:
    Type: AWS::WAF::Rule
    Properties:
      Name: !Sub ${AppName}AllowedRule #ハイフンやアンスコは使用不可
      MetricName: !Sub ${AppName}AllowedRule
      Predicates:
        -
          DataId: !Ref MyIPSet
          Negated: false
          Type: IPMatch

  MyIPSet:
    Type: AWS::WAF::IPSet
    Properties:
      Name: !Sub ${AppName}AllowedIPSet #ハイフンやアンスコは使用不可
      IPSetDescriptors:
        -
          Type: IPV4
          Value: !Sub ${AllowedIP}/32 #IPは末尾に「/32」を付与

AWS::Serverless::Api + AWS::WAFRegional パターン

AWS::WAFRegional の場合、 WebACLAssociation というリソースを利用して紐付けを行います。
公式ドキュメントでは、ロードバランサーとの紐付けの例しかありませんが、API Gateway と紐付けを行う場合は以下のように記述します。

template.yaml(+APIGateway)
Parameters:
  AppName:
    Type: String
  Stage:
    Type: String
  AllowedIP:
    Type: String

Resources:
  MyApi:
    Type: AWS::Serverless::Api
    Properties:
      # 〜その他のプロパティは省略〜
      StageName: !Ref Stage
    
  MyWebACLAssociation: #紐付けはこのリソースで行う
    Type: "AWS::WAFRegional::WebACLAssociation"
    Properties:
      ResourceArn: !Sub arn:aws:apigateway:${AWS::Region}::/restapis/${MyApi}/stages/${Stage}
      # ResourceArn は !Ref MyApi ではないので注意
      WebACLId: !Ref MyWebACL

  MyWebACL:
    Type: AWS::WAFRegional::WebACL
    Properties:
      Name: !Sub ${AppName}APIWebACL #ハイフンやアンスコは使用不可
      DefaultAction:
        Type: BLOCK
      MetricName: !Sub ${AppName}APIWebACL
      Rules:
        -
          Action:
            Type: ALLOW
          Priority: 1
          RuleId: !Ref MyRule

  MyRule:
    Type: AWS::WAFRegional::Rule
    Properties:
      Name: !Sub ${AppName}APIAllowedRule #ハイフンやアンスコは使用不可
      MetricName: !Sub ${AppName}APIAllowedRule
      Predicates:
        -
          DataId: !Ref MyIPSet
          Negated: false
          Type: IPMatch

  MyIPSet:
    Type: AWS::WAFRegional::IPSet
    Properties:
      Name: !Sub ${AppName}APIAllowedIPSet #ハイフンやアンスコは使用不可
      IPSetDescriptors:
        -
          Type: IPV4
          Value: !Sub ${AllowedIP}/32 #IPは末尾に「/32」を付与

最後に

今回は、サーバレスアーキテクチャでの CloudFormation を用いた WAF の設定のハマりポイントを解説しました。
AWSの公式ドキュメントは本当にわかりづらいので、同じようなことでハマっている人は参考にしていただければ幸いです。

20
13
3

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
20
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?