松島


Date/Time: 2020:01:07 09:35:38
Camera: PENTAX
Model: PENTAX K-5 II s
Exporsure Time: 1/6400
FNumber: 5.6
Aperture Value: 5.0
Focal Length: 21.0

Close

y2blog » AWS環境下でのWordPressのセキュリティー対策(WAF2編)

9

23

2022

AWS環境下でのWordPressのセキュリティー対策(WAF2編)

AWS WAF2 でWordpressの管理画面へのアクセスを制限する


WordPressサイトをCloudFront経由で配信する際のキャッシュの制御についてはもう少し検討を重ねなければならないが、CloudFrontとの組み合わせについてはある程度の目処が付いたので、今度はWordpressの管理画面に対する制御について検討することにする.


WordPressサイトを単独で動かしている分には、単純に管理画面へのアクセスを”.htaccess” 等でIPアドレスやドメインベースでアクセス制限を掛けることが可能なので特に問題とはならないが、CloudFrontを経由させると、オリジン側であるHTTPサーバは全てのHTTPトラフィックがCloudFrontからやって来るため、HTTPサーバ側ではユーザのIPアドレスやドメイン情報を基にした単純なアクセス制御ができなくなる.


勿論、”.htaccess”のような単純なアクセス制御ができないけれど、CloudFront側でオリジンリクエストのカスタムポリシーを作成することで、クライアントのIPアドレス情報を取得し、その情報をHTTPヘッダー情報に載せてオリジン側のHTTPサーバへ渡すことが可能なので、オリジンサーバ側の工夫で、ユーザのIP情報に基づいたアクセス制御は可能だ.


参考記事:『[UPDATE] Amazon CloudFrontでクライアントのIPアドレスと接続ポートを確認できるCloudFront-Viewer-Addressヘッダが利用可能になりました』 Developers IO


今回は、オリジン側のサーバにはあまり手を掛けたくないので、CloudFrontと簡単に連携可能な AWS WAF2(旧バージョンと新バージョンの2種類があるので、新バージョンの方を WAF2 と記載することにする)を用いて、Wordpressの管理ページに対してアクセス制限を施すことにする.


AWS WAF2 を設定してみる


AWS WAF2 は今回のCloudFrontのほかに、ロードバランサ(ALB)サービスやAPI Gateway などと組み合わせることが可能なサービスで、1 Web ACLあたり 月額5$(US)、1 Ruleにつき 月額1$(US)、それに 100万リクエストあたり 0.6$(US) の従量料金制となっている.


今回の様な用途にこのWAFサービスを利用するのは大袈裟なのだが、とりあえず検証なのでコストは気にせずに試してみることにする.


AWSの WAF & Shield 管理コンソールから、 “Getting started” でWizard形式で設定作業を進めて行くことが可能だが、今回は先に、自宅や組織のIPアドレス情報を先に “IP sets” という形で登録することから始める.


IP sets の登録


AWS WAFの管理コンソール左端のペインから “IP sets” を選択し、作成するリージョンを選択する.今回は CloudFrontとの連携なので、東京リージョンでは無く “Global(CloudFront)” を選ぶ.

一つの”IP sets”中にIPv4とIPv6を混在させることができないようなので、IPv4とIPv6の2つの “IP sets” を作成する.IPアドレス(CIDR形式)は複数行同時に記載可能だ.


Create IPsets
先ずはIP setsを作成する

IPv4 Set
IPv4のセット
IPv6 Set
IPv6のセット


Registered IP sets
登録した2組のIP sets


WebACLs の登録


IP setsの登録が終わったら、次に今回のWAFの設定のメインパートとなる WebACL の作成に進む.Firewallなどの設定経験があれば画面の設定項目にどのような設定をすれば良いのか分かるだろう.


今回は、管理登録者が利用するIPアドレスをIP sets に登録しているので、アクセスしてきたIPアドレスがこのIP Setsのアドレスに含まれていれば、無条件にアクセス許可とする.このアドレスに登録されていなければ、一般ユーザからのアクセスという事であるので、アクセス先がWordpressの管理エリアであれば、アクセス拒否とし、そうでなければ通常のコンテンツアクセスであるので、アクセスを許可するという設定となる.


この判定を単純化するため、デフォルト動作はアクセス許可(ALlow)に設定しておき、次の順番で判定を実施する.


  1. IP setsと一致する   ⇒ アクセス許可(Allow)
     ↓
  2. 管理URIに一致する  ⇒ アクセス拒否(Block)
     ↓
  3. アクセス許可(Allow)

【 Step 1. WebACLの作成とAWSリソースへの関連付け】


作成するWebACLに適当な名前を付け、”Resource Type” を CloudFront に設定する.その下にある、”Associated AWS resources – optional” で、既に作成してある CloudFront のDistribution への紐付けを行う.


Create WebACL - step1
WebACLの名前を設定し、CloudFrontのDistributionへの紐付けを行う


【 Step 2. ルールの作成】


先ほど定義した、アクセス条件定義をWebACLのルールとして実装する.Rulesの設定から、”Add rules” プルダウンメニューから”Add my own rules and rule groups” を選択する.下部にある “Default web ACL action for requests that don’t match any rules” については、デフォルトのアクションは許可とするので、 ”Allow” を選択する.


Create WebACL - step2
Add my own rules and rule groups 設定画面

Create WebACL - step3
Rule Typeとして”Rule Builder” を選択し、最初のルールを作成する

[ ルール #1 : 管理者のIPアドレス判定 ]

最初のルールは IP sets に含まれているかどうかの判定を行う.Rule名として適当な名前を付け、Typeは “regular rule” を選択する.その下の “If a request” プルダウンメニューの条件として複数の条件が記載されており、

  ”matches the statement”
  ”matches all the statements (AND)”
  ”matches at least one of the statements (OR)”
  ”dose’t match the statement (NOT)”

の4つから選択する.今回は、IPv4 と IPv6 アドレスのどちらか一つに一致するかどうかの判定なので、OR条件である “matches at least one of the statements (OR)” を選択する.


これにより、”Statement 1″ の下部に “Statement 2″ の項目が現れるので、”Statement 1” と同様に “IPv6” の条件を設定する.



WebACL Rule1 - step1
“matches at least one of the statements (OR)” を選び 2つのStatementを”OR” でつなぐ

Inspect のプルダウン項目は、”Originates from an IP address in” を選び、IP sets として、予め登録してある IPv4のIP sets名がプルダウン項目に現れるので、それを選択する.


同様の設定を、”Statement 2″ に対しても行う.



WebACL Rule1 - step2
IPv6のIP setsの判定もルールに加える

最後に、これらの2つの IP sets のどちらかに一致した場合のAction(動作)を設定する.この場合は管理者のアクセスなので、定義に従って “Allow” を設定する.これで最初のルールの定義は完了である.


WebACL Rule1 - step3
管理者からのアクセスルールを満たした場合のアクションは “Allow”(許可)


[ ルール #2 : 管理画面の URL アクセス判定 ]

管理者のIPアドレスによる判定ルールの作成の次に、Wordpressの管理画面のURIへのアクセスかどうかを判定するルールを加える.先ほどと同じように、Rule Typeに”Rule Builder” を選び、同じように 作成するルールにWordpressの管理画面へのアクセスと容易に分かるような適当な名前を付ける.


今回は、”wp-login.php” ファイルのURIと “/wp-admin/” ディレクトリ配下のURIかどうかの判定なので、先ほどの IP アドレス判定と同じように、 “OR” 条件で Statement 1 ( “/wp-admin” )とStatement 2 ( “wp-login.php” ) をつなぐ.


URIの判定は、IPアドレスの判定よりも少し厄介で、ユーザ(クライアントのWEBブラウザ)がどのようなURIで実際にアクセスして来るのか見極めないと、正確なURIアクセスの判定ができない.大文字小文字の扱いやURIエンコーディング、文字列の一致条件など設定する項目は多い.


IP setsと同様に、予め正規表現パターンを登録しておくことが可能なので、よく使う正規表現パターンは登録しておくと良いだろう.


このURIの判定条件の作成は、慣れるまではある程度試行錯誤が必要となるだろう.


【注意】今回のURIの判定条件はこのブログの素材作成のためにとりあえず設定した、いい加減なものなので、実際にルールを作成する場合は各自のWordpress環境に合わせた正確な判定条件を作成する必要がある.



WebACL Rule2 - step1

WordPressの管理画面URIへのアクセスルールを作成する



WebACL Rule2 - step2
2つのURIルールのどちらかに合致するする場合は、”Block” (拒否)とする


[ デフォルトアクションの設定 ]

WebACL作成の最初の段階で、デフォルトのアクションを設定してあるが、作成した2つのルールに該当しない場合は、一般からの正常なWordpressコンテンツへのアクセスであるので、全て “Allow” (許可)とする.


WebACL Rule2 - step3
デフォルトアクションを “Allow” に設定する


[ Step 3. 各ルールの優先順位の設定 ]


今回は、2つのルールしかないが、最初の管理者IPアドレス判定ルールを2番目のWordpressの 管理URI判定ルールよりも優先される必要がある.上記の順番通り作成していれば、最初に作成したルールが上位(優先度が高い)に配置されている筈なので、優先順位を変更する必要はないが、ルールを追加したり条件を変更する場合は、ルール間の順位関係を考慮する必要がある.


この辺のルールの順位やデフォルトアクションとの兼ね合いは、日頃からFirewallの設定を行っていないと難しいかもしれない.本番環境にルールを適用する前に、テスト環境で想定通りに動作する事を確かめておくことを推奨する.



WebACL Rule Priority
各ルールの優先順位を適切に設定する必要がある


【各種メトリックの設定】


この設定は必須ではないが、WAFをAWSのCloudWatchサービスと連携させて WAF2の動作状況を適切に監視させることが可能だ.今回登録したWebACLルールをCloudWatchのメトリックに登録しておく.


Register CW Metrics
作成した2つのWebACLをCloudWatchのメトリックスに加えて監視対象にする



【 Step 5. 設定のレビュー 】


WebACLの作成ウィザードに従って設定を行う最後の作業が、これまでの設定作業内容のレビューを行い、設定が正しいことを確認した後、画面右下の”Create web ACL” ボタンを実行して、WebACLを登録(CloudFrontへの紐付け)する.



WebACL Review - 1
設定したWebACLの内容を確認する

WebACL Review - 2
設定内容に問題がなければ設定したWebACLを有効化しCloudFrontへ紐付ける


CloudWatch Metrics Viewr
WAF2の管理コンソール画面からWebACLへのアクセス状況を見ることができる

WebACL CW Logs
WebACLに対するアクセスログも確認可能



自宅外からのアクセス(今回はLTE接続のiPad)して、Wordpressの管理画面へのアクセスが想定通りの動きになっていることを確認してみる.


Forbidden 403 Error
外部から管理ページ “wp-login.php”へのアクセスは “403 Forbidden” を返すことを確認


【オリジンへの直接アクセスを禁止する】


これまでの設定で、WordpressサイトをCloudFrontとAWS WAFの組み合わせで、セキュリティー対策をある程度施した上で、CloudFrontのキャッシュの恩恵にも授かれる環境を構築することができたが、最後にもう一つやらなければならない、重要なセキュリティー対策がある.


その最後のセキュリティー対策は、今回のオリジンサーバである、AWSのEC2サーバに対して、外部からのHTTP/HTTPSアクセス(勿論その他のサービスポートも含めて)を遮断する必要がある.


外部からオリジンサーバへのアクセスは、全世界のCloudFrontエッジからのアクセスが来るため、CloudFrontのIPアドレスレンジを全て把握した上で、そのIPアドレスのみからHTTPアクセスを受け付けるようにせっていしなければならない.


AWSではCloudFrontのエッジサーバのIPリストを公開している様だが、それらを自分で取得してリジンサーバ側へ反映させるのはかなり手間の掛かる作業であり、CloudFrontサーバの追加や構成変更の度にこれらのホワイトリストを更新しなければならない.


CloudFrontのIPホワイトリストを利用する以外に、CloudFront側から送出されるオリジンへのリクエストヘッダーに手を加えて、オリジン側でCLoudFrontからのアクセスであることを判別させることも可能だ.(『リクエストにカスタム HTTP ヘッダーを追加するための CloudFront 設定』)


Lambda@EdgeをCloudFrontに適用して、かなり細かな制御を行うことも可能なようだ.この辺の対策については、先人達のプラクティスが公開されているので、それらを参考にすると良いだろう.


今回は、DevelopersIO の『【アップデート】Amazon CloudFront を経由しないアクセスのブロックが簡単になりました』を参考に、オリジン側のサーバ上でCloudFront以外のアクセスを禁止することにする.


AWSのEC2を使う場合、セキュリティーグループを利用してアクセス制限を掛けることが一般的に行われているが、今回CloudFront以外のアクセスを禁止するための仕組みとして、AWS側でCloudFrontのアドレス情報を、Managed Prefix Lists としてセキュリティーグループで利用可能な形式で提供してくれている.


先ずは、AWS管理コンソールにアクセスして、VPCサービスの左端のペーンにある、”Managed prefix lists” を選択すると、数個(今回は4個)のprefixリストが一覧表示される.その中に、pl-58a04531 – com.amazonaws.global.cloudfront.origin-facing というprefix listが、今回のCloudFrontのエッジサーバのIPリストだ.


残念ながら現時点ではIPv4アドレスのprefix listsは用意されているようだが、IPv6のprefix listsが見当たらない.CloudFrontからオリジンへの通信がIPv4だけであれば特に問題はないのだが...


VPC Managed IP List
Managed prefix lists から “pl-58a05531” “com.amazonaws.global.cloudfront.origin-facing” を開く

CF Managed IP List
CloudFrontのエッジサーバのIPリストが作成されている


予め自分で登録してあるセキュリティーグループに、このAWS側で作成しているManaged prefix listsからのHTTPアクセスを許可する設定を追加する.今回は自宅からのアクセスのみVPC内へのアクセスを許可しているセキュリティーグループに対して設定を行う.


対象となるセキュリティーグループのinbound ルールに、CloudFrontからのHTTPアクセスのみを許可する設定を追加する.Source をCustomにすると検索リストに上記のCloudFrontのManeged IP List 名(pl-58a05531)が現れるので、それを選んでSource Addressとして設定する.



My Security Groups
予め作成済みのセキュリティーグループのリスト

Adding C FHTTP.Access Rule
セキュリティーグループのリストにCloudFrontからのアクセス許可を加える

これで、セキュリティーグループに、CloudFrontのエッジサーバからのHTTPアクセス許可が追加された.


Access From External NW
自宅外からオリジンサーバ(EC2)へのアクセスができないことを確認

とりあえずAWS上に構築したWordpressサイトをCloudFront, AWS WAFとの組み合わせで、比較的セキュアな環境で稼働させることができた.


WordPressを単純に使っている分には問題はないが、ちょっとでも複雑なことをやろうとすると、途端にWordpress特有の壁にぶち当たってしまう.CMS機能とWebフロントエンドが渾然一体なため、Wordpress内部にFQDN情報を持つなど、WEBエンジニアや管理する立場から見るとWordpress環境を維持・運用していくのはとても骨の折れる作業だ.


何で、CMSが内部にFQDNを抱えているのか理解に苦しむが、長年使い続けてきたWordpress君ともそろそろお別れしなければならない時が来たようだ.WEBエンジニアリングの世界では既に静的コンテンツジェネレーションへの移行がメジャーな流れとなっているようなので、このサイトも折りを見てそちらの方向へ移行しようと思う.


今回検証している WordPress + CloudFront + AWS WAF の環境がまともに稼働してくれるようなら、次の新しい環境へのつなぎとして使ってみようかと思う.


それにしても、WordpressとCDNの組み合わせは相性が悪そうだ.ほんの数日の検証でも色々と不具合や変な挙動に見舞われた.もう少し様子を見てから、今回の検証環境が使い物になるかどうか判定することにしよう.




【後日談】AWSの機能を駆使してセキュアなWordpress環境を維持するのは骨の折れる作業が必要だ.今回は技術的な検証が目的だったので Wordpress + CloudFront + AWS WAFという組み合わせで構築してみたが、この環境を本番環境として今後も運用を続けて行く気にはとてもなれない.


やはりこのブログの様な個人レベルのWordpressサイトでは、運用コストや運用に掛かる労力を考えるととてもじゃないがやってられないというのが本当のところだ....という訳で現在は、このサイトはAWSを離れて、費用の安い国産VPSサーバで運用しているのが実情だ.