Azure の Application Gateway 上でリクエストヘッダー（API キー）を追加して Azure functions を呼べるか調査した

## 調査結果

Application Gateway 経由での、各関数の API キーをリクエストヘッダーに書き換えることは可能。

> 注意：ただし、HTTP ヘッダーの書き換え機能は、**Application Gateway v2 SKU** でのみ使用可能とのこと。

## 根拠

### API キーについて

HTTP トリガーテンプレートでは要求内に API キーを使用する場合の HTTP 要求は通常以下のようになる。

```http
https://<APP_NAME>.azurewebsites.net/api/<FUNCTION_NAME>?code=<API_KEY>
```

つまり、一つの関数アプリ内の関数毎に API キーを適用するには、API キーを `code` というクエリ文字列変数に含めることとなるが、 **`x-functions-keyHTTP` ヘッダーに含めることも可能**とのこと。

> 参考：[関数のアクセスキー](https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-bindings-http-webhook-trigger?tabs=python#function-access-keys)

### Application Gateway について

Application Gateway では、要求・応答の HTTP ヘッダーを書き換えることが可能（ただし **Application Gateway v2 SKU** でのみ）。

以下の「書き換え条件」というオプションを使用して HTTP 要求・応答のコンテンツを評価し、書き換え条件に一致した変数があれば、指定したものに書き換える。

（上記条件に一致しているかの確認は正規表現によるパターンマッチングを使用している。）

- 要求の HTTP ヘッダー
- 応答の HTTP ヘッダー
- Application Gateway のサーバー変数
  - サーバー変数はクエリ情報やポート番号、要求メソッド（GET、POST など）をとれるそう、詳細は最下部。

つまり、関数アプリ内の各関数を特定できる「要求の HTTP ヘッダー」または「Application Gateway のサーバ変数」情報を HTTP 要求として Application Gateway に送ることで、一つの関数アプリ内の各関数毎に意図した API キーを付与することは可能と判断した。

- 各関数毎の API キーを格納するヘッダーは `x-functions-keyHTTP` と考える。

> 参考：[Application Gateway で HTTP ヘッダーと URL を書き換える](https://docs.microsoft.com/ja-jp/azure/application-gateway/rewrite-http-headers-url)

## 実装方法

以下のサイトが参考になる。

- [Azure Application Gateway で HTTP の要求および応答ヘッダーを書き換える - Azure portal](https://docs.microsoft.com/ja-jp/azure/application-gateway/rewrite-http-headers-portal)

大まかにまとめると以下のようになりそう。

1. 要求 URL の情報を「Application Gateway サーバー変数」の `request_uri`、または `uri_paht` で読み取る。
1. Application Gateway の「書き換えセットの作成」で、読み取った URL をもとに、対応する API キーをセットする。

---

## （補足）サーバー変数

Application Gateway では、サーバー変数を使用して、サーバー、クライアントとの接続、およびその接続での現在の要求に関する情報が格納される。

これらの変数を使用して、書き換え条件を評価し、ヘッダーを書き換えることが可能である。

アプリケーション ゲートウェイでは、次のサーバー変数がサポートされている。

| 変数名                    | 説明                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| add_x_forwarded_for_proxy | X-Forwarded-For クライアント要求ヘッダー フィールドと、IP1、IP2、IP3 などの形式でそれに追加される client_ip 変数 (この表で後ほど説明します) が含まれています。 X-Forwarded-For フィールドがクライアント要求ヘッダーにない場合、add_x_forwarded_for_proxy 変数は $client_ip 変数と等しくなります。 この変数は、Application Gateway によって設定された X-Forwarded-For ヘッダーを書き換えるときに特に有用です。この方法により、ヘッダーにはポート情報は含まれず、IP アドレスのみが含まれるようになります。 |
| ciphers_supported         | クライアントでサポートされている暗号の一覧。                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| ciphers_used              | 確立された TLS 接続で使用される暗号の文字列。                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| client_ip                 | アプリケーション ゲートウェイが要求を受信したクライアントの IP アドレス。 アプリケーション ゲートウェイと発信元のクライアントの前にリバース プロキシがある場合、client_ip にはリバース プロキシの IP アドレスが返されます。                                                                                                                                                                                                                                                                              |
| client_port               | クライアント ポート。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| client_tcp_rtt            | クライアント TCP 接続の情報。 TCP_INFO ソケット オプションをサポートするシステムで使用できます。                                                                                                                                                                                                                                                                                                                                                                                                         |
| client_user               | HTTP 認証の使用時に、認証のために提供されるユーザー名。                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| host                      | 優先順位は次のとおりです: 要求行のホスト名、Host 要求ヘッダー フィールドのホスト名、要求に一致するサーバー名。 例: 要求 http://contoso.com:8080/article.aspx?id=123&title=fabrikam では、host 値は contoso.com になります。                                                                                                                                                                                                                                                                              |
| cookie\_ name             | name クッキー。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| http_method               | URL 要求を行うために使用されたメソッド。 たとえば、GET、POST などです。                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| http_status               | セッションの状態。 たとえば、200、400、403 です。                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| http_version              | 要求プロトコル。 通常、HTTP/1.0、HTTP/1.1、または HTTP/2.0 です。                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| query_string              | 要求された URL 内で "?" の後にある、変数と値のペアから成る一覧。 例: 要求 http://contoso.com:8080/article.aspx?id=123&title=fabrikam では、query_string 値は id=123&title=fabrikam になります。                                                                                                                                                                                                                                                                                                          |
| received_bytes            | 要求の長さ (要求行、ヘッダー、および要求本文を含む)。                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| request_query             | 要求行内の引数。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| request_scheme            | 要求スキーム。http または https です。                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| request_uri               | 完全な元の要求 URI (引数を含む)。 例: 要求 http://contoso.com:8080/article.aspx?id=123&title=fabrikam*では、request_uri 値は article.aspx?id=123&title=fabrikam になります。                                                                                                                                                                                                                                                                                                                             |
| sent_bytes                | クライアントに送信されたバイト数。                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| server_port               | 要求を受け付けたサーバーのポート。                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| ssl_connection_protocol   | 確立された TLS 接続のプロトコル。                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| ssl_enabled               | 接続が TLS モードで動作する場合は “オン”。 それ以外の場合は、空の文字列です。                                                                                                                                                                                                                                                                                                                                                                                                                            |
| uri_path                  | Web クライアントがアクセスする必要があるホスト内の特定のリソースを識別します。 これは、引数を含まない要求 URI の部分です。 例: 要求 http://contoso.com:8080/article.aspx?id=123&title=fabrikam では、uri_path 値は article.aspx になります                                                                                                                                                                                                                                                               |

## 参考資料

- [Application Gateway で HTTP ヘッダーと URL を書き換える](https://docs.microsoft.com/ja-jp/azure/application-gateway/rewrite-http-headers-url)