簡単Webサイトホスティング②CloudFrontにWAFをアタッチするCloudFormationテンプレート

# はじめに

Amazon Web Services（AWS）が提供する、``Amazon CloudFront`` や ``Amazon S3`` と呼ばれるサービスを組み合わせることで、 **HTMLやJavaScript、画像、ビデオなどで構成される静的Webサイトの配信基盤** を[**安価に構築**](https://aws.amazon.com/jp/websites/)することができます。本記事では、リソースのセットアップを自動で行うことのできる、``AWS CloudFormation`` を用いることで、これらの配信基盤を **ミスなく迅速に構築** する手順をご説明します。なお、今回使用する CloudFormation テンプレートは、以下の GitHub リポジトリで公開しています。

+ [AWSCloudFormationTemplates/static-website-hosting-with-ssl](https://github.com/eijikominami/aws-cloudformation-templates/blob/master/static-website-hosting-with-ssl/README_JP.md)

# TL;DR

以下の ``CloudFormation`` テンプレートを実行することで、 **静的Webサイトのホスティング基盤** を **迅速かつお手軽に実現** します。下にあるボタンをクリックすると、自身のAWSアカウント（Asia Pacific Tokyo - ap-northeast-1）で、この ``CloudFormation`` テンプレートを実行することが可能となります。

[![cloudformation-launch-stack](https://raw.githubusercontent.com/eijikominami/aws-cloudformation-templates/master/images/cloudformation-launch-stack.png)](https://console.aws.amazon.com/cloudformation/home?region=ap-northeast-1#/stacks/create/review?stackName=StaticWebsiteHosting&templateURL=https://eijikominami.s3-ap-northeast-1.amazonaws.com/aws-cloudformation-templates/static-website-hosting-with-ssl/template.yaml) 

作成されるAWSリソース全体のアーキテクチャ図は、[**前回の記事**](https://qiita.com/eijikominami/items/13ebbb2c44a62c71aee7)をご覧ください。このうち本記事では、以下のリソースに焦点を当ててご説明します。

![architecture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51599/cf983606-3678-ab86-9f3d-3710dbbcd695.png)


# Amazon CloudFront への AWS WAF のアタッチ

AWS WAFは、Webの脆弱性からWebアプリケーションを保護する **Web Application Firewall** で、 SQLインジェクションやクロスサイトスクリプティングなどの **一般的な攻撃パターンをブロック** します。静的Webサイトのホスティング機能の一部を担う [**CloudFrontに AWS WAFをアタッチする**](https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/distribution-web-awswaf.html)ことで、CloudFrontへの **リクエストのモニタリング** 、およびコンテンツへの **アクセスのコントロール** を可能とします。

## AWS WAF

以下のテンプレートを用いて、AWS WAFを設定します。なお、 **CloudFrontにアタッチするWAFは、北部バージニアリージョン（us-east-1）でデプロイ** しなければいけません。

```yaml
Resources:
  WebACL:
    Type: AWS::WAFv2::WebACL
    Properties: 
      DefaultAction: 
        Allow: {}
      Description: !Sub ACL for ${LogicalNamePrefix}
      Name: !Ref LogicalNamePrefix
      Rules: 
        - Name: AWSManagedRulesCommonRuleSet
          OverrideAction:
            Count: {}
          Priority: 1
          Statement: 
            ManagedRuleGroupStatement: 
              Name: AWSManagedRulesCommonRuleSet
              VendorName: AWS
          VisibilityConfig: 
            CloudWatchMetricsEnabled: true
            MetricName: AWSManagedRulesCommonRuleSet
            SampledRequestsEnabled: false
        - Name: AWSManagedRulesAdminProtectionRuleSet
          OverrideAction:
            Count: {}
          Priority: 2
          Statement: 
            ManagedRuleGroupStatement: 
              Name: AWSManagedRulesAdminProtectionRuleSet
              VendorName: AWS
          VisibilityConfig: 
            CloudWatchMetricsEnabled: true
            MetricName: AWSManagedRulesAdminProtectionRuleSet
            SampledRequestsEnabled: false
        - Name: AWSManagedRulesKnownBadInputsRuleSet
          OverrideAction:
            Count: {}
          Priority: 3
          Statement: 
            ManagedRuleGroupStatement: 
              Name: AWSManagedRulesKnownBadInputsRuleSet
              VendorName: AWS
          VisibilityConfig: 
            CloudWatchMetricsEnabled: true
            MetricName: AWSManagedRulesKnownBadInputsRuleSet
            SampledRequestsEnabled: false
        - Name: AWSManagedRulesAmazonIpReputationList
          OverrideAction:
            Count: {}
          Priority: 4
          Statement: 
            ManagedRuleGroupStatement: 
              Name: AWSManagedRulesAmazonIpReputationList
              VendorName: AWS
          VisibilityConfig: 
            CloudWatchMetricsEnabled: true
            MetricName: AWSManagedRulesAmazonIpReputationList
            SampledRequestsEnabled: false
      Scope: CLOUDFRONT
      VisibilityConfig: 
        CloudWatchMetricsEnabled: true
        MetricName: !Ref LogicalNamePrefix
        SampledRequestsEnabled: false
  WebACLAssociation:
    Type: AWS::WAFv2::WebACLAssociation
    Properties: 
      ResourceArn: !Ref TargetResourceArn
      WebACLArn: !GetAtt WebACL.Arn
```

本テンプレートでは、 **Default Action** を ``Allow`` に設定しており、 **Ruleに一致しないリクエストは全て許可** します。また、WAFv2から導入された以下の **マネージドルールを有効化** して、これらの **ルールに一致するリクエストをカウント** します。なお、 [**CloudWatchへメトリクスを送信**](https://docs.aws.amazon.com/ja_jp/waf/latest/developerguide/monitoring-cloudwatch.html) しますが、[リクエストのサンプルの保存](https://docs.aws.amazon.com/ja_jp/waf/latest/developerguide/web-acl-testing.html#web-acl-testing-view-sample)は行いません。CloudFrontにアタッチするWAFの ``Scope`` は **CLOUDFRONT** を指定します。

| 優先順位 | ルール名 | 内容 |
| --- | --- | --- |
| 1 | AWSManagedRulesCommonRuleSet | 一般的に適用可能なルール |
| 2 | AWSManagedRulesAdminProtectionRuleSet | 公開されている管理ページへの外部アクセスをブロックするためのルール |
| 3 | AWSManagedRulesKnownBadInputsRuleSet | 無効であることがわかっており脆弱性の悪用または発見に関連するリクエストパターンをブロックするルール |
| 4 | AWSManagedRulesAmazonIpReputationList | Amazon 内部脅威インテリジェンスに基づくルール |

## Amazon CloudFront

先ほど作成した ``AWS WAF`` を ``Amazon CloudFront`` にアタッチします。[**前回のテンプレート**](https://qiita.com/eijikominami/items/13ebbb2c44a62c71aee7)に以下の記述を追加します。

```yaml
Resources:
  CloudFront:
    Type: 'AWS::CloudFront::Distribution'
    Properties:
      DistributionConfig:
        WebACLId: !GetAtt WebACL.Arn
```

以上で、 **マネージドルールを有効化したAWS WAFを作成して、CloudFrontにアタッチ** することができました。これにより、CloudFront へのリクエストは、 **AWS WAF で検査されたのちに CloudFront ディストリビューションで処理** されます。

# 関連リンク
1. [**ワンクリックで配信基盤を構築** - CloudFormation を用いて簡単Webサイトホスティング](https://qiita.com/eijikominami/items/13ebbb2c44a62c71aee7)
2. **CloudFrontにWAFをアタッチ** - CloudFormation を用いて簡単Webサイトホスティング
3. [**特定のURLを定期的にモニタリングする** - CloudFormation を用いて簡単Webサイトホスティング](https://qiita.com/eijikominami/items/45162d01edeec2855141)
4. [**CloudFrontのリアルタイムログをKibanaで可視化する** - CloudFormation を用いて簡単Webサイトホスティング](https://qiita.com/eijikominami/items/1bcde04897b5136e4122)