Azure アプリケーションゲートウェイ(Application Gateway)で書き換え(rewrite)を設定する方法をまとめます。書き換え(rewrite)の機能を使うとHTTPヘッダーやURLの書き換えをする事ができます。
前提
公式ドキュメント
参考になる公式ドキュメントを以下に示します。
- Application Gateway で HTTP ヘッダーと URL を書き換える
- Azure Application Gateway で HTTP の要求および応答ヘッダーを書き換える
- Azure Application Gateway を使用して URL を書き換える
事前設定
以下、リソースグループを作成します。
az group create --name MyResourceGroup --location japaneast
以下、仮想ネットワークを作成します。
az network vnet create \ --resource-group MyResourceGroup \ --name MyVnet \ --address-prefix 172.16.0.0/16 az network vnet subnet create \ --resource-group MyResourceGroup \ --name Subnet01 \ --vnet-name MyVnet \ --address-prefixes 172.16.1.0/24 az network vnet subnet create \ --resource-group MyResourceGroup \ --name Subnet02 \ --vnet-name MyVnet \ --address-prefixes 172.16.2.0/24
アプリケーションゲートウェイを作成します。
az network public-ip create \ --resource-group MyResourceGroup \ --name MyPublicAddress \ --sku Standard az network application-gateway create \ --name MyAppGateway \ --resource-group MyResourceGroup \ --capacity 2 \ --sku Standard_v2 \ --public-ip-address MyPublicAddress \ --vnet-name MyVnet \ --subnet Subnet01
アプリケーションゲートウェイ配下に仮想マシンを配置します。
az vm create \ --resource-group MyResourceGroup \ --name linux010 \ --image UbuntuLTS \ --size Standard_B1s \ --admin-username azureuser \ --ssh-key-values ~/.ssh/authorized_keys \ --vnet-name MyVnet \ --subnet subnet02 \ --private-ip-address 172.16.2.10 az network nic ip-config address-pool add \ --resource-group MyResourceGroup \ --nic-name linux010VMNic \ --ip-config-name ipconfiglinux010 \ --gateway-name MyAppGateway \ --address-pool appGatewayBackendPool
HTTP response headerの書き換え
事前準備
Azureに構築された仮想マシンにsshログインし、apache httpdをインストールします。
sudo apt -y install apache2
アプリケーションゲートウェイに付与されたパブリックIPアドレスを確認し、Azureの外からHTTPによるリクエストが可能である事を確認します。
後述の操作で、HTTP reponse headerの「Server」と「Last-Modified」を書き換えますので、デフォルト設定の値をメモに控えてください。
admin@mac19 ~ % az network public-ip show \ --resource-group MyResourceGroup \ --name MyPublicAddress \ --query "ipAddress" "20.222.163.175" admin@mac19 ~ % admin@mac19 ~ % admin@mac19 ~ % curl -v -s 20.222.163.175 > /dev/null * Trying 20.222.163.175:80... * Connected to 20.222.163.175 (20.222.163.175) port 80 (#0) > GET / HTTP/1.1 > Host: 20.222.163.175 > User-Agent: curl/7.77.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < Date: Sun, 01 May 2022 07:43:32 GMT < Content-Type: text/html < Content-Length: 10918 < Connection: keep-alive < Server: Apache/2.4.29 (Ubuntu) < Last-Modified: Sun, 01 May 2022 07:40:51 GMT < ETag: "2aa6-5ddee651d61d3" < Accept-Ranges: bytes < Vary: Accept-Encoding < { [1169 bytes data] * Connection #0 to host 20.222.163.175 left intact admin@mac19 ~ %
HTTPヘッダーの書き換え – ヘッダの削除
HTTPヘッダー書き換え設定の前にrewrite rule setと呼ばれる書き換えの設定集の名前を定義する必要があります。
az network application-gateway rewrite-rule set create \ --gateway-name MyAppGateway \ --resource-group MyResourceGroup \ --name MyRewriteRuleSet
az network application-gateway rewrite-rule createコマンドの引数response-headersにヘッダーの書き換えを指定します。基本的にHEADER=VALUEの書式で指定します。もし、ヘッダーを削除するならばHEADER=’ ‘と指定します。
以下はapache2というミドルウェア名を公表する事が脆弱性につながるとの思想から、ミドルウェア名を非公開にする設定例です。
az network application-gateway rewrite-rule create \ --gateway-name MyAppGateway \ --resource-group MyResourceGroup \ --rule-set-name MyRewriteRuleSet \ --name Rule100 \ --sequence 100 \ --response-headers Server=''
rewrite rule setをルールに適用します。
az network application-gateway rule update \ --gateway-name MyAppGateway \ --resource-group MyResourceGroup \ --name rule1 \ --rewrite-rule-set MyRewriteRuleSet
設定後、確かにServerヘッダーが削除されている事を確認します。
admin@mac19 ~ % curl -v -s 20.222.163.175 > /dev/null * Trying 20.222.163.175:80... * Connected to 20.222.163.175 (20.222.163.175) port 80 (#0) > GET / HTTP/1.1 > Host: 20.222.163.175 > User-Agent: curl/7.77.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < Date: Sun, 01 May 2022 08:26:49 GMT < Content-Type: text/html < Content-Length: 10918 < Connection: keep-alive < Last-Modified: Sun, 01 May 2022 07:40:51 GMT < ETag: "2aa6-5ddee651d61d3" < Accept-Ranges: bytes < Vary: Accept-Encoding < { [1201 bytes data] * Connection #0 to host 20.222.163.175 left intact admin@mac19 ~ %
HTTPヘッダーの書き換え – 条件に応じた書き換え例
Last-Modifiedに検索順位変動があるかどうか調査するブラックハットSEOの仮説検証を例にした設定例を紹介します。
以下のようにLast-Modifiedを変更するような設定を投入します。
az network application-gateway rewrite-rule create \ --gateway-name MyAppGateway \ --resource-group MyResourceGroup \ --rule-set-name MyRewriteRuleSet \ --name Rule110 \ --sequence 110 \ --response-headers Last-Modified='Sun, 31 May 2099 23:59:59 GMT'
この変更が全てのHTTPリクエストに影響を与えるのは影響範囲が大きいので、User-Agentがgoogle botの場合のみに限定します。
引数variableにはHTTPヘッダーを表す変数を指定します。変数の命名規則は「http_req_<ヘッダー名>」です。引数patternは合致する場合のパターンを正規表現で指定します。
az network application-gateway rewrite-rule condition create \ --gateway-name MyAppGateway \ --resource-group MyResourceGroup \ --rule-set-name MyRewriteRuleSet \ --rule-name Rule110 \ --variable http_req_User-Agent \ --pattern '.*bot.*'
User-Agentを指定せずにHTTPリクエストを送ります。この場合は条件に一致しないので、Last-Modifiedは初期設定のままです。
admin@mac19 ~ % curl -v -s 20.222.163.175 > /dev/null * Trying 20.222.163.175:80... * Connected to 20.222.163.175 (20.222.163.175) port 80 (#0) > GET / HTTP/1.1 > Host: 20.222.163.175 > User-Agent: curl/7.77.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < Date: Sun, 01 May 2022 08:33:19 GMT < Content-Type: text/html < Content-Length: 10918 < Connection: keep-alive < Last-Modified: Sun, 01 May 2022 07:40:51 GMT < ETag: "2aa6-5ddee651d61d3" < Accept-Ranges: bytes < Vary: Accept-Encoding < { [1201 bytes data] * Connection #0 to host 20.222.163.175 left intact admin@mac19 ~ %
User-Agentにgooglebotを指定してHTTPリクエストを送ります。この場合は条件に一致するので、Last-Modifiedが書き換えられている事が分かります。
admin@mac19 ~ % curl -v -s 20.222.163.175 \ -H 'User-Agent:Googlebot/2.1' > /dev/null * Trying 20.222.163.175:80... * Connected to 20.222.163.175 (20.222.163.175) port 80 (#0) > GET / HTTP/1.1 > Host: 20.222.163.175 > Accept: */* > User-Agent:Googlebot/2.1 > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < Date: Sun, 01 May 2022 08:34:38 GMT < Content-Type: text/html < Content-Length: 10918 < Connection: keep-alive < Last-Modified: Sun, 31 May 2099 23:59:59 GMT < ETag: "2aa6-5ddee651d61d3" < Accept-Ranges: bytes < Vary: Accept-Encoding < { [10918 bytes data] * Connection #0 to host 20.222.163.175 left intact admin@mac19 ~ %
HTTP request headerの書き換え
事前準備
HTTP request headerをデバッグしやすいようにphpinfoを表示できるよう設定します。
$ sudo su - # apt install -y php libapache2-mod-php # echo '<?php phpinfo(); ?>' > /var/www/html/info.php # systemctl restart apache2
ブラウザでphpinfoが閲覧できる事を確認します。
HTTPヘッダーの書き換え
認証アプリケーションと業務アプリケーションが別チームによる開発をするような環境で、認証アプリケーション完成前に業務アプリケーションのテストをしたいような要件を想定します。最終的な構成は認証アプリケーションがHTTP requestのAuthorizationヘッダーを付与しますが、それまでの臨時対応としてアプリケーションゲートウェイがHTTP requestのAuthorizationヘッダーを付与します。
azコマンドによる設定例は以下の通りです。
az network application-gateway rewrite-rule create \ --gateway-name MyAppGateway \ --resource-group MyResourceGroup \ --rule-set-name MyRewriteRuleSet \ --name Rule200 \ --sequence 200 \ --request-headers Authorization='Bearer XXXXXXXXXXXXXXXXXXXXX'
動作確認
ブラウザでphpinfoを閲覧し、確かにHTTP requestのAuthorizationヘッダーが付与されている事を確認します。
サーバ変数を利用した書き換え
サーバ変数の一覧
書き換えの条件一致は以下のようなコマンドで定義できます。このコマンドの引数variableには「サーバ変数」または「HTTPヘッダー」を指定できます。
az network application-gateway rewrite-rule condition create \ --gateway-name <アプリケーションゲートウェイ名> \ --resource-group <リソースグループ名> \ --rule-set-name <ルールセット名> \ --rule-name <ルール名> \ --variable <サーバ変数 または HTTPヘッダー> \ --pattern <正規表現>
指定可能なサーバ変数の一覧は以下のコマンドで調査できます。
$ az network application-gateway rewrite-rule condition list-server-variables [ "request_query", "client_ip", "client_port", "client_user", "http_method", "request_uri", "http_version", "ciphers_used", "ssl_connection_protocol", "http_status", "request_scheme", "sent_bytes", "server_name", "server_port", "ciphers_supported", "client_tcp_rtt", "content_length", "content_type", "host", "ssl_enabled", "add_x_forwarded_for_proxy", "query_string", "received_bytes", "uri_path", "client_certificate", "client_certificate_fingerprint", "client_certificate_serial", "client_certificate_subject", "client_certificate_issuer", "client_certificate_start_date", "client_certificate_end_date", "client_certificate_verification" ]
URLの書き換え
操作説明
それではサーバ変数uri_pathの書き換え例を紹介します。
一般的にSEOでは「article.html?author=hiroshi-abe&title=why-not-do-your-best」のようなクエリ文字列よりも「article/hiroshi-abe/why-not-do-your-best」のような階層構造のURLの方が望ましいと言われています。ユーザや検索エンジンから見れば階層構造のURLの方が見やすいですが、開発者から見ればクエリ文字列の方が取り扱いが容易です。
このような事情を踏まえ、近年のWebアプリケーションフレームワークでは階層構造のURLをクエリ文字列に変換する機能が備わっています。これをAzure アプリケーションゲートウェイで実装してみましょう。
コマンドの意味の説明は後述しますが、以下コマンドを実行します。処理完了まで30分程の時間を要するため、no-waitオプションを付与して実行するようにしましょう。
az network application-gateway rewrite-rule create \ --gateway-name MyAppGateway \ --resource-group MyResourceGroup \ --rule-set-name MyRewriteRuleSet \ --name Rule300 \ --sequence 300 \ --modified-path '/info.php' \ --modified-query-string 'author={var_uri_path_1}&title={var_uri_path_2}' \ --no-wait az network application-gateway rewrite-rule condition create \ --gateway-name MyAppGateway \ --resource-group MyResourceGroup \ --rule-set-name MyRewriteRuleSet \ --rule-name Rule300 \ --variable var_uri_path \ --pattern '/article/(.*)/(.*)' \ --no-wait
処理が完了したかどうかは以下のように調べます。「Updating」が「Succeeded」に変わるまで待ちます。
$ az network application-gateway show \ --name MyAppGateway \ --resource-group MyResourceGroup \ --query "provisioningState" "Updating"
変数操作の説明
サーバ変数は「var_<変数名>」の書式でazコマンドの引数variableに与える事ができます。引数patternに指定する正規表現は、丸括弧(…)を使用したグループ化の機能を使用する事ができます。以下に、URL書き換えの条件一致指定を再掲します。
az network application-gateway rewrite-rule condition create \ --gateway-name MyAppGateway \ --resource-group MyResourceGroup \ --rule-set-name MyRewriteRuleSet \ --rule-name Rule300 \ --variable var_uri_path \ --pattern '/article/(.*)/(.*)' \ --no-wait
このような正規表現を使用すると、URLが「/article/hiroshi-abe/why-not-do-your-best」の場合は、第1グループは「hiroshi-abe」で第2グループは「why-not-do-your-best」になります。
これらグループを書き換え(rewrite)で操作するには以下のような変数を指定します。
変数 | 意味 |
---|---|
var_uri_path_1 | 変数var_uri_pathを正規表現でマッチングし、第1グループに該当する部分 |
var_uri_path_2 | 変数var_uri_pathを正規表現でマッチングし、第2グループに該当する部分 |
以下に、URL書き換えを再掲します。引数modified-query-stringに正規表現の第1グループと第2グループにマッチした部分を指定します。
az network application-gateway rewrite-rule create \ --gateway-name MyAppGateway \ --resource-group MyResourceGroup \ --rule-set-name MyRewriteRuleSet \ --name Rule300 \ --sequence 300 \ --modified-path '/info.php' \ --modified-query-string 'author={var_uri_path_1}&title={var_uri_path_2}' \ --no-wait
疎通確認
このようなルールを定義すると、URLは以下のように変換されるはずです。
[変換前] http://<ip_address>/article/hiroshi-abe/why-not-do-your-best [変換後] http://<ip_address>/info.php?author=hiroshi-abe&title=why-not-do-your-best
実際に想定通りのURL変換がなされている事をブラウザで確認します。
もし、ブラウザでの確認が不安でしたら、アクセスログから確認しても良いでしょう。
azureuser@linux010:~$ sudo tail -n1 -f /var/log/apache2/access.log 172.16.1.7 - - [02/May/2022:08:51:21 +0000] "GET / HTTP/1.1" 200 244 "-" "-" 172.16.1.6 - - [02/May/2022:08:51:46 +0000] "GET /info.php?author=hiroshi-abe&title=why-not-do-your-best HTTP/1.1" 200 22027 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:99.0) Gecko/20100101 Firefox/99.0"
正規表現に基づくHTTP headerの書き換え
事前準備
HTTP responseのLocation headerを例に挙げて、正規表現に基づくヘッダーの書き換え操作を説明します。まずはLocation headerを返すように、apache httpdで.htaccessを用いたリダイレクトを設定します。
仮想マシンへsshでログインし、AllowOverrideをNoneからAllに変更します。
sudo sed -i -e 's/AllowOverride None/AllowOverride All/g' /etc/apache2/apache2.conf sudo systemctl restart apache2
apache2のrewriteモジュールを有効にします。
sudo a2enmod rewrite sudo systemctl restart apache2
以下のような.htaccessを準備します。
sudo su - cat << EOF > /var/www/html/.htaccess <IfModule mod_rewrite.c> RewriteEngine on RewriteCond %{HTTP_HOST} ^www\.gokatei.net$ RewriteRule ^(.*)$ http://www.gokatei.com/$1 [R=302] RewriteCond %{HTTP_HOST} ^test\.gokatei.net$ RewriteRule ^(.*)$ http://test.gokatei.com/$1 [R=302] </IfModule> EOF
このような設定によってホストヘッダーが「www.gokatei.net」または「test.gokatei.net」の時にリダイレクトされるようになりました。想定通りのリダイレクトがなされるかどうかを動作確認します。
admin@mac19 ~ % curl -s -v -H 'Host:www.gokatei.net' \ 20.222.163.175/test.html > /dev/null * Trying 20.222.163.175:80... * Connected to 20.222.163.175 (20.222.163.175) port 80 (#0) > GET /test.html HTTP/1.1 > Host:www.gokatei.net > User-Agent: curl/7.77.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 302 Found < Date: Mon, 02 May 2022 09:39:22 GMT < Content-Type: text/html; charset=iso-8859-1 < Content-Length: 297 < Connection: keep-alive < Server: Apache/2.4.29 (Ubuntu) < Location: http://www.gokatei.com/test.html < { [297 bytes data] * Connection #0 to host 20.222.163.175 left intact admin@mac19 ~ % admin@mac19 ~ % admin@mac19 ~ % curl -s -v -H 'Host:test.gokatei.net' \ 20.222.163.175/test.html > /dev/null * Trying 20.222.163.175:80... * Connected to 20.222.163.175 (20.222.163.175) port 80 (#0) > GET /test.html HTTP/1.1 > Host:test.gokatei.net > User-Agent: curl/7.77.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 302 Found < Date: Mon, 02 May 2022 09:39:25 GMT < Content-Type: text/html; charset=iso-8859-1 < Content-Length: 299 < Connection: keep-alive < Server: Apache/2.4.29 (Ubuntu) < Location: http://test.gokatei.com/test.html < { [299 bytes data] * Connection #0 to host 20.222.163.175 left intact admin@mac19 ~ %
HTTPヘッダーの書き換え
操作説明
htaccessによって「gokatei.net」から「goketei.com」への移行を遂行しました。次に「gokatei.com」から「gokatei.co.jp」に移行します。htaccessは何らかの要件によって編集不能の状況で、アプリケーションゲートウェイを用いてドメイン移行しなければならない状況を想定します。
コマンドの意味は後述しますが、この要件を実現するコマンドは以下の通りです。
az network application-gateway rewrite-rule create \ --gateway-name MyAppGateway \ --resource-group MyResourceGroup \ --rule-set-name MyRewriteRuleSet \ --name Rule400 \ --sequence 400 \ --response-headers location=http://{http_resp_Location_1}.gokatei.co.jp/{http_resp_Location_2} az network application-gateway rewrite-rule condition create \ --gateway-name MyAppGateway \ --resource-group MyResourceGroup \ --rule-set-name MyRewriteRuleSet \ --rule-name Rule400 \ --variable http_resp_Location \ --pattern 'http://(.*)\.gokatei.com/(.*)'
変数操作の説明
HTTP requestヘッダーとHTTP responseヘッダーのそれぞれは変数「http_req_<ヘッダー名>」「http_resp_<ヘッダー名>」の書式でazコマンドの引数variableに与える事ができます。引数patternに指定する正規表現は、丸括弧(…)を使用したグループ化の機能を使用する事ができます。以下に、ヘッダー書き換えの条件一致指定を再掲します。
az network application-gateway rewrite-rule condition create \ --gateway-name MyAppGateway \ --resource-group MyResourceGroup \ --rule-set-name MyRewriteRuleSet \ --rule-name Rule400 \ --variable http_resp_Location \ --pattern 'http://(.*)\.gokatei.com/(.*)'
このような正規表現を使用すると、Locationが「http://www.gokatei.com/test.html」の場合は、第1グループは「www」で第2グループは「test.html」になります。
これらグループを書き換え(rewrite)で操作するには以下のような変数を指定します。
変数 | 意味 |
---|---|
http_resp_Location_1 | 変数http_resp_Locationを正規表現でマッチングし、第1グループに該当する部分 |
http_resp_Location_2 | 変数http_resp_Locationを正規表現でマッチングし、第2グループに該当する部分 |
以下に、ヘッダーの書き換えを再掲します。引数response-headersに正規表現の第1グループと第2グループにマッチした部分を指定します。
az network application-gateway rewrite-rule create \ --gateway-name MyAppGateway \ --resource-group MyResourceGroup \ --rule-set-name MyRewriteRuleSet \ --name Rule400 \ --sequence 400 \ --response-headers location=http://{http_resp_Location_1}.gokatei.co.jp/{http_resp_Location_2}
疎通確認
HTTP responseヘッダーが想定通りに書き換えられ、想定通りのresponseを返す事を確認します。
admin@mac19 ~ % curl -s -v -H 'Host:www.gokatei.net' \ 20.222.163.175/inquiry.html > /dev/null * Trying 20.222.163.175:80... * Connected to 20.222.163.175 (20.222.163.175) port 80 (#0) > GET /inquiry.html HTTP/1.1 > Host:www.gokatei.net > User-Agent: curl/7.77.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 302 Found < Date: Mon, 02 May 2022 09:43:02 GMT < Content-Type: text/html; charset=iso-8859-1 < Content-Length: 300 < Connection: keep-alive < Server: Apache/2.4.29 (Ubuntu) < location: http://www.gokatei.co.jp/inquiry.html < { [300 bytes data] * Connection #0 to host 20.222.163.175 left intact admin@mac19 ~ % admin@mac19 ~ % admin@mac19 ~ % curl -s -v -H 'Host:test.gokatei.net' \ 20.222.163.175/inquiry.html > /dev/null * Trying 20.222.163.175:80... * Connected to 20.222.163.175 (20.222.163.175) port 80 (#0) > GET /inquiry.html HTTP/1.1 > Host:test.gokatei.net > User-Agent: curl/7.77.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 302 Found < Date: Mon, 02 May 2022 09:43:09 GMT < Content-Type: text/html; charset=iso-8859-1 < Content-Length: 302 < Connection: keep-alive < Server: Apache/2.4.29 (Ubuntu) < location: http://test.gokatei.co.jp/inquiry.html < { [302 bytes data] * Connection #0 to host 20.222.163.175 left intact admin@mac19 ~ %