AWS WAFを利用してCloudFrontのELBオリジンへ直接アクセスを制限してみた

· 5 min read
AWS WAFを利用してCloudFrontのELBオリジンへ直接アクセスを制限してみた

こんぬつわ。だいぶ久しぶりの更新となります。

ELBの前段にCloudFrontを設置した環境では、CloudFrontとオリジンのELB間の通信はインターネット経由で行われます。

ELBのIPやDNS名を知った利用者による、CloudFrontを経由しないELBへの直接アクセスが望ましくない場合には、 CloudFrontのカスタムヘッダを利用したアクセス制限が可能です。

環境

  • CloudFrontはカスタムオリジンとしてAWS東京リージョンのELBを指定
  • ELBはALB(アプリケーションロードバランサ)を利用
  • ALB配下のEC2、OSはAmazonLinux、Webサーバとして、httpd(Apache)をデフォルト状態で利用
  • ALBの前段にAWS WAFを設置し、特定のCloudFrontを経由しないアクセスを禁止

やってみた

▼EC2つくる

今回はEC2のインスタンスタイプをt4g.nanoにしました。
最近リリースされたばっかなのでちょっと使いたかったのです。
検証で使うだけなのでスペックは最低限でOK

1. とりあえずyum updateして再起動

# yum -y update
# reboot

2.apacheインストール。デフォの2.4でいいでしょ。

# yum -y install httpd
# systemctl enable httpd
# systemctl start httpd

3. ALBヘルスチェック用のファイルを作っておく。今回はhealth.htmlという名前にしました。

# vi /var/www/html/health.html
---------------------------
OK
---------------------------

4.セキュリティグループで80番の全許可を入れておく
※ページ確認用とALBからのヘルスチェック用

3. サーバにアクセス

http://[IP]/
※以下のページ表示になればOK。駄目ならApache上がってるかSGの設定見直してみてね。

▼ELBつくる
今回はALBにしましょう。

ALB名は適当にtestとかにしておきます。
AvailabilityZoneはVPCのデフォa~d全部を選択
セキュリティグループは80番をlistenしてるものをつかいます。
※Cloudfrontと通信通すために必要なので
それ以外はそのままの設定で。

▼TargetGroupつくる

作成途中で聞かれるので新しく作成しましょう。
名前は同じくtest、ヘルスチェックの部分だけhealth.htmlを選択します。

次の画面で登録するターゲット聞かれるので
先程作成したEC2インスタンス(test)を登録しましょう。
そこまでいったらALBの作成完了です。

▼ALBとEC2の動作確認

作成したTargetGroup、testにEC2がhealthyで紐付いているか確認
うまくいけばStatusがhealthになっているはず

 

 

アクセスログにもヘルスチェックのログでてる。

# tail -f /var/log/httpd/access.log
172.31.37.12 - - [20/Oct/2020:17:29:39 +0000] "GET /health.html HTTP/1.1" 200 3 "-" "ELB-HealthChecker/2.0"
172.31.5.68 - - [20/Oct/2020:17:29:53 +0000] "GET /health.html HTTP/1.1" 200 3 "-" "ELB-HealthChecker/2.0"
172.31.37.12 - - [20/Oct/2020:17:30:09 +0000] "GET /health.html HTTP/1.1" 200 3 "-" "ELB-HealthChecker/2.0"
172.31.5.68 - - [20/Oct/2020:17:30:23 +0000] "GET /health.html HTTP/1.1" 200 3 "-" "ELB-HealthChecker/2.0"
172.31.37.12 - - [20/Oct/2020:17:30:39 +0000] "GET /health.html HTTP/1.1" 200 3 "-" "ELB-HealthChecker/2.0"
172.31.5.68 - - [20/Oct/2020:17:30:53 +0000] "GET /health.html HTTP/1.1" 200 3 "-" "ELB-HealthChecker/2.0"
172.31.37.12 - - [20/Oct/2020:17:31:09 +0000] "GET /health.html HTTP/1.1" 200 3 "-" "ELB-HealthChecker/2.0"

ELBのDNS名にアクセスして正常にアクセスできればOK

http://[ELB名].ap-northeast-1.elb.amazonaws.com/

もしUnhealthyになるようであればSGの設定かヘルスチェックの設定見直してみてね。

▼CloudFront作る

Origin Domain Nameのところは作成したELBを選択します。たぶん候補に出てくるはず。
Origin Pathは/でいいかな。

で、ここでポイント。
Origin Custom Headersとして、ヘッダ名「x-pre-shared-key」、値は「hdserver-only-hash」を指定しました。
実環境でアクセス制限に利用する場合、カスタムヘッダの値は推測されにくい文字列の利用をお勧めします。

検証用なので、その他の設定はデフォルトのままでいいと思います。
必要に応じてHTTPS対応させたり、Cname設定してみてください。

作成後にDistribution StatusがDeployedになれば作成完了。
Cloudfront側で割り当てられたDomainNameにアクセスしてデフォ表示になればOK

*******.cloudfront.net

▼AWS WAF設定

CloudFrontで定義したカスタムヘッダをもつリクエストのみ、アクセスを許可する設定を行います。

ACL設定

  • Web ACLを作成します
  • 任意のACL名称と、アクセス制限対象となるELB(ALB)を指定します

Add rules and rule groupsの画面でAdd my own rules and rule groupsを選択
Rule builderで名前は任意のもの、TypeはRegularRule、If a requestはmatches the statementにします。

HTTPヘッダ「x-pre-shared-key」、その値が「hdserver-only-hash」に一致するフィルタを定義します。
マッチした場合のルールはAllowにします。Default の挙動はBlockにしましょう。

▼作成完了&動作確認

ACLの作成まできたら作成完了となります。
早速動作確認してみましょう。

CloudFront

  • CloudFront(カスタムヘッダ設定済み)経由のアクセスは可能です。

ELB直接

  • ELBのDNS名を直接指定した場合、AWS WAFによりアクセス禁止となりました

おしまい

直リンク禁止とかにも応用できるので、他サイトからの引用を制限することもできますね。
ちなみにEC2、ELB、Cloudfront、AWS WAFといろいろなサービスを使っているので
ずっと上げっぱなしだと何もしなくても月3,000円くらいかかります。しんどい。

検証なので、落ち着いたら全部消し去ります。

http://test-950671320.ap-northeast-1.elb.amazonaws.com/
http://dulrpil4kzexo.cloudfront.net/

▼参考サイト
https://dev.classmethod.jp/articles/restrict-elb-origin-awswaf/