CloudFront + ALB + WAFの検証

## はじめに
WAFを触ってみたかったので検証しました。

## 構成
![WAF.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812406/3f930728-d43b-4387-a4ea-0877c5dd47c9.png)



## 前提
ユーザーデータでEC2にApachをインストールしてHello Worldしています。
```
UserData: 
  Fn::Base64: |
    #! /bin/bash
    yum update -y
    yum install -y httpd

    echo "<html><body><h1>Hello World</h1></body></html>" > /var/www/html/index.html

    touch /var/www/html/.check_alive
    chown apache:apache -R /var/www/html

    systemctl start httpd.service
    systemctl enable 
```

### WAFルール
- リソースはCloudFrontを選択する

![20250222_000000.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812406/e4215901-d19f-46e7-9427-2351cf3cd46b.jpeg)
![20250222_000001.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812406/36db81b6-2163-49be-bcd9-624305463ff2.jpeg)
- ルールに一致しない場合にトラフィックを許可する
- 無料のSQLインジェクションをブロックするルールで作成します
![20250222_000002.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812406/b9d42ffc-d66c-4737-a374-5f8cae7fc460.jpeg)

### IPset
作成した web ACL にアクセスを許可するIPアドレスを追加し、優先度で許可したIPリストを最後に評価するように設定します。今回は自宅のIPを許可リストに入れています。
下記のIPsetを作成し、上のルールに追加します。
![20250222_000008.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812406/d2e2a2d0-fce3-4837-9c5c-45459177e48e.jpeg)

## CloudFront
#### CFnテンプレート（WebACL適用）
```
AWSTemplateFormatVersion: "2010-09-09"
Resources:  
  CloudFrontDistribution:
    Type: AWS::CloudFront::Distribution
    Properties:
      DistributionConfig:
        Origins:
          - DomainName: example.com  ## 独自ドメイン
            Id: example.com
            CustomOriginConfig:
              HTTPPort: 80
              HTTPSPort: 443
              OriginProtocolPolicy: match-viewer
        Enabled: true
        DefaultCacheBehavior:
          TargetOriginId: example.com
          ViewerProtocolPolicy: allow-all
          AllowedMethods: 
            - GET
            - HEAD
            - OPTIONS
            - PUT
            - POST
            - PATCH
            - DELETE
          CachedMethods: 
            - GET
            - HEAD
            - OPTIONS
          CachePolicyId: "4135ea2d-6df8-44a3-9df3-4b5a84be39ad"  # CatchingDisabled  
          OriginRequestPolicyId: "b689b0a8-53d0-40ab-baf2-68738e2966ac"  # AllViewerExceptHostHeader
          ForwardedValues:
            QueryString: false
            Cookies:
              Forward: none
        WebACLId: arn:aws:wafv2:us-east-1:<アカウントID>:global/webacl/<WebACLの名前>/<WebACLのID> # WebACL
        PriceClass: PriceClass_All
        Restrictions:
          GeoRestriction:
            RestrictionType: none
        IPV6Enabled: false    

Outputs:
  CloudFrontURL:
    Description: "CloudFront URL"
    Value: !Sub "https://${CloudFrontDistribution.DomainName}"          
```
## テスト
```
$ curl https://d3i6dnmf977sr1.cloudfront.net
<html><body><h1>Hello World</h1></body></html>
```
- SQLインジェクション
- 以下のクエリが実行されるような引数をつけてアクセスしてみる
```
SELECT * FROM users WHERE key='10' or '1'='1';
```
```
$ curl https://d3i6dnmf977sr1.cloudfront.net/?key=%2710%27%20or%20%271%27%3d%271%27
<!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: tIeDx_hISel3C-3VvUikIPnRCBON0H2kJkRHquvfWCyLu1pE53Vj_A==
</PRE>
<ADDRESS>
</ADDRESS>
</BODY></HTML>
```

ステータスコードは403エラーでリクエストがWAFによってブロックされていることがわかります。

## 最後に
今回は簡単なルールでの検証だったが、理解度を高めて要件に合わせたチューニングができるようになりたい