Azureの「App Service」で、サイトコンテンツへのアクセスをクライアント(ソース)IPアドレスで制限する方法は幾つかある。そのうち、内蔵のWebサーバ「NGINX」の設定を変更すると、App Service単体でディレクトリ単位でのアクセス制御を実現できる。その手順と注意点を説明する。
対象:Azure App Service on Linux(NGINX内蔵)
広く一般公開しているWebサイトでも、一部コンテンツは管理者だけにアクセスを限定したい。そのような要件はよくあることだ。
こうしたアクセス制限を手っ取り早く実装する方法の一つとして、特定のソースIP(クライアントIP)アドレスを判定して、アクセス許可/拒否を決めるというものがある。ユーザーを特定できずとも(会社などの)組織を限定できれば十分という場合によく用いられる。
しかしAzureの「App Service」の場合、標準かつ内蔵の機能だとサイト全体でしか制限できない。ほとんどのコンテンツは一般公開のまま、特定のコンテンツのみを制限したい場合は、Front Doorなどの外部サービスの助けが必要になり、追加コストが必要になってしまう。
実はApp Service on Linuxであれば、内蔵のWebサーバ「NGINX」の設定を書き換えることで、月々のクラウド料金を増やすことなく、特定ディレクトリに対するクライアントIPアドレスでのアクセス制限を実装することが可能だ。本Tech TIPSでは、その具体的な手順と注意点を説明する。
App Service内蔵のNGINXの設定変更については、「【Azure】App ServiceのWebサーバ『NGINX』をカスタマイズする方法」を前提としている。
また、App ServiceのランタイムスタックはPHP 8.3とする。その他のスタックではスタートアップスクリプト(後述)の名称や内容が異なる、といった違いがあるので注意していただきたい。
まず、許可または拒否するクライアントIPアドレスを定義する設定ファイルを用意する。ここでは[/home/custom/etc/nginx/inc]というフォルダを新設し、そこに[restrict-by-ip.conf]という設定ファイルを以下のように記述する。
# restrict-by-ip.conf: クライアントIPアドレスごとのアクセス許可/拒否を決定する
# 取引先のIPv4アドレス(1つ)を許可
allow 192.0.2.3;
# ISP1から割り当てられたIPv4(複数)を許可/拒否
deny 198.51.100.14; # このIPのみ拒否
allow 198.51.100.8/29; # その他のサブネット内IPは許可
# ISP2から割り当てられたIPv6の一部を許可
allow 2001:db8:2:3:4:5::/96;
# 上記以外は全て拒否
deny all;
クライアントIPアドレスは上記リストの上から一致した順に許可/拒否が判定される。例えば「198.51.100.13」であれば「allow 198.51.100.8/29;」によってアクセスが許可される。一方、どれにも該当しないIPアドレスは最終行の「deny all;」によってアクセスが拒否される。
上記リストは、後述の[sites-available/default]に直接記述することも可能だ。ただ、別ファイルに格納した方が、複数のディレクトリを容易に制限できる他、複雑になりやすい[sites-available/default]のシンプルに維持しやすい、といったメリットがある。
次に、正しいクライアントIPアドレスを取得するための設定と、制限対象のディレクトリに関する設定を、[sites-available/default]に記載する。
server {
#proxy_cache cache;
#proxy_cache_valid 200 1s;
listen 8080;
listen [::]:8080;
root /home/site/wwwroot;
index index.php index.html index.htm;
server_name example.com www.example.com;
port_in_redirect off;
# ---------- 以下を挿入 ----------
# 正しいクライアントIPアドレスを取得するための設定
real_ip_header X-Forwarded-For;
set_real_ip_from 169.254.0.0/16;
# 管理専用の「/kanrishanoheya」ディレクトリ以下は、
# 特定のクライアントIPアドレスからのアクセスだけを許可
location ~ ^/kanrishanoheya/ {
# IP制限を記述した設定ファイルを読み込む
include inc/restrict-by-ip.conf;
# 必要なら他のディレクティブをここに記述
}
# ---------- 挿入終わり ----------
location / {
index index.php index.html index.htm hostingstart.html;
}
<後略>
}
上記で挿入している「real_ip_header」「set_real_ip_from」ディレクティブは、NGINXとクライアントの間にリバースプロキシまたはロードバランサーなどが存在している状況で、実際のクライアントのIPアドレスを導出するためのものだ。
App Serviceも、標準でクライアントとの間にロードバランサーが配置されている。デフォルト設定のままだと、前述の「allow」「deny」ディレクティブにはクライアントIPアドレスではなくロードバランサーのIPアドレスが伝わるため、意図した通りに制限できない。前出の[inc/restrict-by-ip.conf]の場合、全てのクライアントからのアクセスが拒否されてしまうので注意してほしい。
そこで、まず「real_ip_header」に、経路上の各ロードバランサー/リバースプロキシがクライアントのIPアドレスを記載するヘッダー名称を指定する。App Serviceの場合は「X-Forwarded-For」を指定すればよい。
次に、各ロードバランサー/リバースプロキシが取り得るIPアドレスを列挙して、「set_real_ip_from」に記載する。App Serviceの場合は「169.254.0.0/16」を指定すること。
以上により、ロードバランサー/リバースプロキシの先にあるクライアントIPアドレス(発信元IPアドレス)がNGINXで正しく取り扱えるようになる。前述の「allow」「deny」ディレクティブにも、本当のクライアントIPアドレスが伝わり、意図通りに制限できるようになる。
注意すべきは、「real_ip_header」「set_real_ip_from」ディレクティブをNGINXの設定ファイルのhttpコンテキストに記述しても、その中にあるserverコンテキストには反映されない、という点だ。そのため、[nginx.conf]や[conf.d/*.conf]ではなく、上記リストのように[sites-available/default]のserverコンテキスト内に記述する必要がある。
ここまでの手順で各設定ファイルを追加/修正したら、Tech TIPS「【Azure】App ServiceのWebサーバ『NGINX』をカスタマイズする方法」の手順3〜5で説明しているように、動作確認をしてから[/home/startup.sh]に反映して、App Serviceを再起動する。
#!/usr/bin/env bash
# 設定ファイルを変更または差し替える
ln -snf /home/custom/etc/nginx/sites-available/default /etc/nginx/sites-available/default
ln -snf /home/custom/etc/nginx/inc /etc/nginx/inc
# NGINXに設定ファイルを再度読み込ませる
nginx -s reload
設定ファイルが正しければ、許可していないIPアドレスから指定のディレクトリ以下(ここでは「/kanrishanoheya/」以下)のコンテンツをWebブラウザで開こうとすると、以下のように「403 Forbidden」が発生し、本来のコンテンツは表示されないはずだ。
Tech TIPS「【Azure】App Service on LinuxにBASIC認証を実装する方法と注意点」で説明しているように、「Always On(常時接続)」「正常性チェック」のプローブのアクセス先に何らかのアクセス制限を施すと、インスタンスが異常と見なされる恐れがある。
具体的には「/」(ルート」と正常性チェックのプローブパスについては、クライアントIPアドレスでの制限を加えないようにする。制限したいディレクトリ(パス)だけをlocationディレクティブに指定して、他に影響しないようにアクセス制限を設定した方がよい。
もし、クライアントとApp Serviceの間に、Front Doorのようなリバースプロキシ/ロードバランサーが加わっている場合は、それらのIPアドレスも「set_real_ip_from」に追記する必要がある。そうしないと、本来のクライアントのIPアドレスがApp Serviceに伝わらなくなってしまうからだ。
さらに、「real_ip_recursive on;」というディレクティブも追記して、多段のリバースプロキシ/ロードバランサーに対応させる必要もある。
この辺りの詳細については、機会があれば別の記事で詳しく説明したい。
■関連リンク
Copyright© Digital Advantage Corp. All Rights Reserved.