Application Load Balancerでパス毎にIPアドレスを制限する方法をまとめてみた
こんにちは、AWS事業本部の荒平(@0Air)です。
最近、Application Load Balancerでパス毎にIP制限を掛けたいという要望を受けました。
アプリケーション側で処理できるなら手っ取り早いですが、難しいケースもあるかもしれません。
Developers IOの記事でもいくつか制限を掛ける方法は紹介されており、ページ下部の参考資料に記載しています。
ただ、方法が色々あるために混乱しそうになったので、一旦まとめることにしました。
概要
そもそも、Application Load Balancer(以下、ALB)にIPアドレス単位でのアクセス制限を行う場合は、主に3つの手段が存在します。
※ API GatewayやNLBなどを組み合わせることでも可能ですが、構成が複雑になるため今回は除外しています
- ALB + Security Group
- ALBにアタッチされているセキュリティグループで許可IPを設定する方法
- 不許可IPを設定することはできない
- 特定のパスにのみ設定はできない(全てのパスで適用される)
- ALB リスナールール
- ALBのリスナールールを作成し、送信元IPを許可設定する方法
- 不許可IPを設定することはできない
- 特定のパスを指定することができる
- パスルールは細かい指定が難しい
- ALB + AWS WAF
- ALBにAWS WAFをアタッチし、IP setで許可・不許可設定する方法
- 不許可IPを設定できる
- 特定のパスを指定することができる
- パスルールは細かい指定が可能
まとめると以下のような表になります。
項目 | ALB + Security Group | ALB リスナールール | ALB + AWS WAF |
---|---|---|---|
全てのパスに 許可IPアドレスの設定 (ホワイトリスト) |
◯ | ◯ | ◯ |
特定のパスのみ 許可IPアドレスの設定 |
✕ | ◯ | ◯ |
不許可IPアドレスの設定 (ブラックリスト) |
✕ | ✕ | ◯ |
本エントリのゴール
本エントリでお伝えしたい内容は以上ですが、せっかくなのであまり検索でヒットしないパターンを検証します。条件は次の通りです。
- 特定パスのみインターネット公開(制限なし)
- 上記の特定パス以外はIPアドレスを制限
この2つの条件をクリアできるように進めます。
なお、この条件とは逆で、「特定パスのみIPアドレス制限、それ以外は制限なし」のケースはリスナールールのみで実現可能なため、以下の記事をご参照ください。
ただし、ALBはリスナールール1つにつき、IPアドレスの登録上限は5つ(パス条件とANDする場合は4つ)のため、多くのIPアドレス制限を掛ける場合はAWS WAFを用いたほうが管理上良いと考えます。
検証してみた
構成図
許可されているIPアドレスはWAF, ALBを経由してEC2の全てのパスにアクセスできます。
許可されていないIPアドレスは、例として/Page-A
にのみアクセスを許可するようにしました。
(1) 検証用のEC2, ALBを作成
検証用のEC2, ALBを作成しました。詳細は割愛しますが、EC2のユーザーデータは以下のように記述しました。
#!/bin/bash # Apacheのインストール yum update -y yum install -y httpd # サービスの起動と自動起動の設定 systemctl start httpd systemctl enable httpd # ディレクトリの作成 mkdir -p /var/www/html/page-a mkdir -p /var/www/html/page-b mkdir -p /var/www/html/page-c # HTMLファイルの作成 echo "Hello World! Page-A" > /var/www/html/page-a/index.html echo "Hello World! Page-B" > /var/www/html/page-b/index.html echo "Hello World! Page-C" > /var/www/html/page-c/index.html # Apacheの設定更新 cat <<EOL > /etc/httpd/conf.d/pages.conf <Directory "/var/www/html/page-a"> Options Indexes FollowSymLinks AllowOverride None Require all granted </Directory> <Directory "/var/www/html/page-b"> Options Indexes FollowSymLinks AllowOverride None Require all granted </Directory> <Directory "/var/www/html/page-c"> Options Indexes FollowSymLinks AllowOverride None Require all granted </Directory> EOL # Apacheの再起動 systemctl restart httpd
何も設定していない状態では、Page-A, Page-B, Page-Cのパスにそれぞれアクセスできる状態です。
http://test-arap-xxx.ap-northeast-1.elb.amazonaws.com/page-a/ http://test-arap-xxx.ap-northeast-1.elb.amazonaws.com/page-b/ http://test-arap-xxx.ap-northeast-1.elb.amazonaws.com/page-c/
今回の条件は「①特定パスのみインターネット公開(制限なし)」「②特定パス以外はIPアドレス制限」なので、Page-Aを公開したまま、Page-A以外をIPアドレス制限します。
※ この例では、「Page-A以外」は「Page-B, C」と判明していますが、これは本来不明であるものとします。
(2) AWS WAFのWeb ACLを作成・ALBにアタッチ
AWS WAFの画面でWeb ACLを作成し、テスト用のALBにアタッチします。
このとき、ルールはALBと同一のリージョンに作成します。
(3) 必要なルールを設定
WebACLにルールを設定します。今回の条件で必要なのは、以下3つのルールです。
- リクエストURIパスが
/Page-A
から始まる場合は、/Page-A
へのアクセスを許可 - リクエストURIパスが
/Page-A
以外、かつ、IPアドレスが事前定義のIP Setに一致する場合は許可 - 上記に一致しない場合はブロック(拒否)
まずは、リクエストURIパスが Page-A
にマッチした場合のルールを作成します。
項目 | 値 |
---|---|
Name | 任意 |
Type | Regular rule |
Inspect | URI Path |
Match type | Starts with string |
String to match | /page-a |
Action | Allow |
続いて、/Page-A
以外のアクセスにIP一致を求めるルールを作成します。
項目 | 値 |
---|---|
Name | 任意 |
Type | Regular rule |
If a request | matches all the statements (AND) |
Statement 1 | - |
Inspect | Originates from an IP address in |
IP set | 許可するIP Set |
IP address to use as the originating address | Source IP address |
NOT Statement 2 | - |
Inspect | URI Path |
Match type | Starts with string |
String to match | /page-a |
Action | Allow |
最後に、どのルールにも一致しないリクエストをブロックする設定にします。
(4) 動作検証
まずは許可IPアドレスからアクセスを行ったところ、想定通り3URLともにアクセスできました。
$ curl http://test-arap-XXX.ap-northeast-1.elb.amazonaws.com/page-a/ Hello World! Page-A $ curl http://test-arap-XXX.ap-northeast-1.elb.amazonaws.com/page-b/ Hello World! Page-B $ curl http://test-arap-XXX.ap-northeast-1.elb.amazonaws.com/page-c/ Hello World! Page-C
続いて許可IPアドレス外からアクセスを行ったところ、こちらも想定通り、/Page-A
のみアクセスでき、それ以外のページ(/Page-B, /Page-C
)へはアクセスできませんでした。
$ curl http://test-arap-XXX.ap-northeast-1.elb.amazonaws.com/page-a/ Hello World! Page-A $ curl http://test-arap-XXX.ap-northeast-1.elb.amazonaws.com/page-b/ <html> <head><title>403 Forbidden</title></head> <body> <center><h1>403 Forbidden</h1></center> </body> </html> $ curl http://test-arap-XXX.ap-northeast-1.elb.amazonaws.com/page-c/ <html> <head><title>403 Forbidden</title></head> <body> <center><h1>403 Forbidden</h1></center> </body> </html>
おわりに
前述の通り、ALBはリスナールール1つにつき、IPアドレスの登録上限は5つ(パス条件とANDする場合は4つ)のため、多くのIPアドレス制限を掛ける場合は、AWS WAFを用いましょう。
(リスナールールを複数作成すれば、この上限は関係ないのですが、構成がカオスになりやすくなります)
また、WAFではNOTステートメントがあるため、ブラックリスト型の制御を行いやすいのが利点です。
料金との兼ね合いもありますが、要件に応じて、適切なアクセス制限方法を選ぶことをおすすめします。
このエントリが誰かの助けになれば幸いです。
それでは、AWS事業本部 コンサルティング部の荒平(@0Air)がお送りしました!