
Application Load Balancerでパス毎にIPアドレスを制限する方法をまとめてみた
この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは、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)がお送りしました!











